diff --git a/.github/ISSUE_TEMPLATE/epic.md b/.github/ISSUE_TEMPLATE/epic.md new file mode 100644 index 00000000000..7e9a32ab454 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/epic.md @@ -0,0 +1,77 @@ +--- +name: Epic +about: Umbrella issue for a major initiative tracked via sub-issues. +title: "Epic: " +labels: epic +--- + + + +This Epic is for ... + + + +## Status + + + +**Proposed.** + +## Goal + + + +## Motivation + + + +## Unresolved questions + + + +- [ ] None yet. diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md new file mode 100644 index 00000000000..a5a8a66d869 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -0,0 +1,98 @@ +--- +name: Tracking Issue +about: A tracking issue for a feature or initiative in Vortex. +title: "Tracking Issue: " +labels: tracking-issue +--- + + + +This is a tracking issue for ... + + + +## Motivation + + + +## Design + + + +## Steps + + + +- [ ] Initial implementation +- [ ] Documentation +- [ ] Public API stabilization + +## Unresolved questions + + + +- [ ] None yet. + +## Implementation history + + diff --git a/.github/runs-on.yml b/.github/runs-on.yml index b1bfde5c961..6a904a6a10d 100644 --- a/.github/runs-on.yml +++ b/.github/runs-on.yml @@ -1 +1,6 @@ _extends: .github-private +images: + ubuntu24-full-arm64-pre: + platform: "linux" + arch: "arm64" + ami: "ami-08f97c6362847dc5d" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6f47fb3b8e1..0acb0a15a55 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,7 +2,7 @@ name: Close inactive PRs on: schedule: - cron: "30 1 * * *" - workflow_dispatch: + workflow_dispatch: { } jobs: close-issues: diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml index 67d54c48508..b429e398b3b 100644 --- a/.github/workflows/web.yml +++ b/.github/workflows/web.yml @@ -7,7 +7,7 @@ concurrency: cancel-in-progress: true on: - pull_request: + pull_request: { } push: branches: [develop] diff --git a/.yamllint.yaml b/.yamllint.yaml index 5fd2694dabf..85f7142a9a9 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -29,7 +29,7 @@ rules: document-end: disable document-start: disable empty-lines: enable - empty-values: disable + empty-values: enable float-values: disable hyphens: enable indentation: enable @@ -38,9 +38,10 @@ rules: line-length: disable new-line-at-end-of-file: enable new-lines: enable - octal-values: disable + octal-values: enable quoted-strings: quote-type: double required: false trailing-spaces: enable - truthy: disable + truthy: + check-keys: false diff --git a/Cargo.lock b/Cargo.lock index 7292f998922..f9fd5e6e960 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -967,7 +967,7 @@ dependencies = [ "bitflags", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -1421,7 +1421,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.8.9", ] [[package]] @@ -1488,7 +1488,7 @@ checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" dependencies = [ "serde", "termcolor", - "unicode-width 0.1.14", + "unicode-width 0.2.2", ] [[package]] @@ -1995,12 +1995,12 @@ dependencies = [ [[package]] name = "cudarc" -version = "0.18.2" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa12038120eb13347a6ae2ffab1d34efe78150125108627fd85044dd4d6ff1e" +checksum = "f071cd6a7b5d51607df76aa2d426aaabc7a74bc6bdb885b8afa63a880572ad9b" dependencies = [ "half", - "libloading", + "libloading 0.9.0", ] [[package]] @@ -3666,7 +3666,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", - "similar", + "similar 3.1.0", "tokio", "tracing", "vortex", @@ -4734,7 +4734,7 @@ checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e" dependencies = [ "console 0.16.3", "once_cell", - "similar", + "similar 2.7.0", "tempfile", ] @@ -4918,7 +4918,7 @@ dependencies = [ "java-locator", "jni-macros", "jni-sys 0.4.1", - "libloading", + "libloading 0.8.9", "log", "simd_cesu8", "thiserror 2.0.18", @@ -5658,6 +5658,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link", +] + [[package]] name = "liblzma" version = "0.4.6" @@ -6874,7 +6884,7 @@ checksum = "044b1fa4f259f4df9ad5078e587b208f5d288a25407575fcddb9face30c7c692" dependencies = [ "rand 0.9.4", "socket2", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -7081,7 +7091,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" dependencies = [ "heck", - "itertools 0.10.5", + "itertools 0.14.0", "log", "multimap", "petgraph", @@ -7113,7 +7123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.117", @@ -8543,6 +8553,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "similar" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d93e861ede2e497b47833469b8ec9d5c07fa4c78ce7a00f6eb7dd8168b4b3f" +dependencies = [ + "bstr", +] + [[package]] name = "similar-asserts" version = "1.7.0" @@ -8550,7 +8569,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b441962c817e33508847a22bd82f03a30cff43642dc2fae8b050566121eb9a" dependencies = [ "console 0.15.11", - "similar", + "similar 2.7.0", ] [[package]] @@ -8677,7 +8696,7 @@ dependencies = [ "owo-colors", "rand 0.8.6", "regex", - "similar", + "similar 2.7.0", "subst", "tempfile", "thiserror 2.0.18", @@ -10283,7 +10302,7 @@ name = "vortex-cub" version = "0.1.0" dependencies = [ "bindgen", - "libloading", + "libloading 0.8.9", "paste", "vortex-array", "vortex-cuda-macros", @@ -10692,6 +10711,7 @@ dependencies = [ "vortex-io", "vortex-mask", "vortex-metrics", + "vortex-runend", "vortex-scan", "vortex-sequence", "vortex-session", @@ -10724,7 +10744,7 @@ name = "vortex-nvcomp" version = "0.1.0" dependencies = [ "bindgen", - "libloading", + "libloading 0.8.9", "liblzma", "reqwest 0.13.2", "tar", diff --git a/Cargo.toml b/Cargo.toml index 4ddcfbe3d43..7770a59d03d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,14 +120,13 @@ chrono = "0.4.42" clap = "4.5" criterion = "0.8" crossterm = "0.29" -cudarc = { version = "0.18.2", features = [ +cudarc = { version = "0.19.0", features = [ # The NSight Compute version available on lambda.ai hosts does not inject a symbol for # several functions that cudarc expects to load when this is set to "cuda-12080". We # don't use any CUDA 12.8 specific features currently so this is fine. "cuda-12050", ] } custom-labels = "0.4.4" -daachorse = "1.0.0" dashmap = "6.1.0" datafusion = { version = "53", default-features = false, features = ["sql"] } datafusion-catalog = { version = "53" } @@ -227,7 +226,7 @@ serde_json = "1.0.138" serde_test = "1.0.176" sha2 = "0.11.0" simdutf8 = "0.1.5" -similar = "2.7.0" +similar = "3.0.0" sketches-ddsketch = "0.4.0" smol = "2.0.2" static_assertions = "1.1" @@ -347,6 +346,8 @@ mem_forget = "deny" multiple_crate_versions = "allow" needless_range_loop = "allow" or_fun_call = "deny" +ref_option = "deny" +ref_option_ref = "deny" panic = "deny" # panic_in_result_fn = "deny" -- we cannot disable this for tests to use assertions clone_on_ref_ptr = "deny" diff --git a/README.md b/README.md index b36509bdc1b..df5a70c09d7 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ [Join the community on Slack!](https://vortex.dev/slack) | [Documentation](https://docs.vortex.dev/) | [Performance Benchmarks](https://bench.vortex.dev) +If you are interested in closer collaboration, please email info@vortex.dev + ## Overview Vortex is a next-generation columnar file format and toolkit designed for high-performance data processing. diff --git a/benchmarks-website/package-lock.json b/benchmarks-website/package-lock.json index d140b73d225..3ac868cf12a 100644 --- a/benchmarks-website/package-lock.json +++ b/benchmarks-website/package-lock.json @@ -8,808 +8,58 @@ "name": "vortex-benchmarks-website", "version": "2.0.0", "dependencies": { - "chart.js": "^4.4.4", - "chartjs-plugin-zoom": "^2.0.1", + "chart.js": "^4.5.1", + "chartjs-plugin-zoom": "^2.2.0", "downsample": "^1.4.0", "hammerjs": "^2.0.8", - "lucide-react": "^0.577.0", - "react": "^18.3.1", - "react-chartjs-2": "^5.2.0", - "react-dom": "^18.3.1" + "lucide-react": "^1.11.0", + "react": "^19.2.5", + "react-chartjs-2": "^5.3.1", + "react-dom": "^19.2.5" }, "devDependencies": { - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "concurrently": "^8.2.2", - "vite": "^6.0.0" + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "concurrently": "^9.2.1", + "vite": "^8.0.10" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "tslib": "^2.4.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "tslib": "^2.4.0" } }, "node_modules/@kurkle/color": { @@ -818,31 +68,39 @@ "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", "license": "MIT" }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", - "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", - "cpu": [ - "arm" - ], + "node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "funding": { + "url": "https://github.com/sponsors/Boshen" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", - "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", "cpu": [ "arm64" ], @@ -851,12 +109,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", - "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", "cpu": [ "arm64" ], @@ -865,12 +126,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", - "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", "cpu": [ "x64" ], @@ -879,26 +143,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", - "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", - "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", "cpu": [ "x64" ], @@ -907,84 +160,36 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", - "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", - "cpu": [ - "arm" ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", - "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", "cpu": [ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", - "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", - "cpu": [ - "arm64" ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", - "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", - "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", - "cpu": [ - "loong64" - ], - "dev": true, "libc": [ "glibc" ], @@ -992,14 +197,17 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", - "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", "cpu": [ - "loong64" + "arm64" ], "dev": true, "libc": [ @@ -1009,50 +217,19 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", - "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", - "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", "cpu": [ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", - "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", - "cpu": [ - "riscv64" - ], - "dev": true, "libc": [ "glibc" ], @@ -1060,29 +237,15 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", - "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", - "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", "cpu": [ "s390x" ], @@ -1094,12 +257,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", - "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "cpu": [ "x64" ], @@ -1111,12 +277,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", - "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", "cpu": [ "x64" ], @@ -1128,26 +297,15 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", - "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", - "cpu": [ - "x64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", - "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", "cpu": [ "arm64" ], @@ -1156,54 +314,51 @@ "optional": true, "os": [ "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", - "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", - "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", "cpu": [ - "ia32" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", - "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", - "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", "cpu": [ "x64" ], @@ -1212,113 +367,79 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } + "license": "MIT" }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/types": "^7.28.2" + "tslib": "^2.4.0" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/hammerjs": { "version": "2.0.46", "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", "license": "MIT" }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/react": { - "version": "18.3.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", - "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "@rolldown/pluginutils": "1.0.0-rc.7" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } } }, "node_modules/ansi-regex": { @@ -1347,74 +468,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.21", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.21.tgz", - "integrity": "sha512-Q+rUQ7Uz8AHM7DEaNdwvfFCTq7a43lNTzuS94eiWqwyxfV/wJv+oUivef51T91mmRY4d4A1u9rcSvkeufCVXlA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001790", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", - "integrity": "sha512-bOoxfJPyYo+ds6W0YfptaCWbFnJYjh2Y1Eow5lRv+vI2u8ganPZqNm1JwNh0t2ELQCqIWg4B3dWEusgAmsoyOw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1506,40 +559,30 @@ "license": "MIT" }, "node_modules/concurrently": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", - "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.1.2", - "date-fns": "^2.30.0", - "lodash": "^4.17.21", - "rxjs": "^7.8.1", - "shell-quote": "^1.8.1", - "spawn-command": "0.0.2", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.2" + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" }, "engines": { - "node": "^14.13.0 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -1547,39 +590,14 @@ "dev": true, "license": "MIT" }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=8" } }, "node_modules/downsample": { @@ -1588,13 +606,6 @@ "integrity": "sha512-teYPhUPxqwtyICt47t1mP/LjhbRV/ghuKb/LmFDbcZ0CjqFD31tn6rVLZoeCEa1xr8+f2skW8UjRiLiGIKQE4w==", "license": "MIT" }, - "node_modules/electron-to-chromium": { - "version": "1.5.343", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.343.tgz", - "integrity": "sha512-YHnQ3MXI08icvL9ZKnEBy05F2EQ8ob01UaMOuMbM8l+4UcAq6MPPbBTJBbsBUg3H8JeZNt+O4fjsoWth3p6IFg==", - "dev": true, - "license": "ISC" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1602,48 +613,6 @@ "dev": true, "license": "MIT" }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1687,16 +656,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1736,83 +695,288 @@ "node": ">=8" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, - "bin": { - "loose-envify": "cli.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/lucide-react": { - "version": "0.577.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.577.0.tgz", - "integrity": "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.11.0.tgz", + "integrity": "sha512-UOhjdztXCgdBReRcIhsvz2siIBogfv/lhJEIViCpLt924dO+GDms9T7DNoucI23s6kEPpe988m5N0D2ajnzb2g==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1832,13 +996,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/node-releases": { - "version": "2.0.38", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", - "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", - "dev": true, - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1860,9 +1017,9 @@ } }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz", + "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==", "dev": true, "funding": [ { @@ -1889,13 +1046,10 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } @@ -1911,26 +1065,15 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "react": "^19.2.5" } }, "node_modules/require-directory": { @@ -1943,50 +1086,46 @@ "node": ">=0.10.0" } }, - "node_modules/rollup": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", - "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "node_modules/rolldown": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.2", - "@rollup/rollup-android-arm64": "4.60.2", - "@rollup/rollup-darwin-arm64": "4.60.2", - "@rollup/rollup-darwin-x64": "4.60.2", - "@rollup/rollup-freebsd-arm64": "4.60.2", - "@rollup/rollup-freebsd-x64": "4.60.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", - "@rollup/rollup-linux-arm-musleabihf": "4.60.2", - "@rollup/rollup-linux-arm64-gnu": "4.60.2", - "@rollup/rollup-linux-arm64-musl": "4.60.2", - "@rollup/rollup-linux-loong64-gnu": "4.60.2", - "@rollup/rollup-linux-loong64-musl": "4.60.2", - "@rollup/rollup-linux-ppc64-gnu": "4.60.2", - "@rollup/rollup-linux-ppc64-musl": "4.60.2", - "@rollup/rollup-linux-riscv64-gnu": "4.60.2", - "@rollup/rollup-linux-riscv64-musl": "4.60.2", - "@rollup/rollup-linux-s390x-gnu": "4.60.2", - "@rollup/rollup-linux-x64-gnu": "4.60.2", - "@rollup/rollup-linux-x64-musl": "4.60.2", - "@rollup/rollup-openbsd-x64": "4.60.2", - "@rollup/rollup-openharmony-arm64": "4.60.2", - "@rollup/rollup-win32-arm64-msvc": "4.60.2", - "@rollup/rollup-win32-ia32-msvc": "4.60.2", - "@rollup/rollup-win32-x64-gnu": "4.60.2", - "@rollup/rollup-win32-x64-msvc": "4.60.2", - "fsevents": "~2.3.2" - } + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "dev": true, + "license": "MIT" }, "node_modules/rxjs": { "version": "7.8.2", @@ -1999,23 +1138,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/shell-quote": { "version": "1.8.3", @@ -2040,12 +1166,6 @@ "node": ">=0.10.0" } }, - "node_modules/spawn-command": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", - "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", - "dev": true - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2124,56 +1244,24 @@ "dev": true, "license": "0BSD" }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, "node_modules/vite": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", - "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -2182,14 +1270,15 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -2198,13 +1287,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { + "optional": true + }, + "jiti": { "optional": true }, - "lightningcss": { + "less": { "optional": true }, "sass": { @@ -2258,13 +1350,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/benchmarks-website/package.json b/benchmarks-website/package.json index 6cda687b838..879aea5857c 100644 --- a/benchmarks-website/package.json +++ b/benchmarks-website/package.json @@ -13,20 +13,20 @@ "node": ">=18.0.0" }, "dependencies": { - "chart.js": "^4.4.4", - "chartjs-plugin-zoom": "^2.0.1", + "chart.js": "^4.5.1", + "chartjs-plugin-zoom": "^2.2.0", "downsample": "^1.4.0", "hammerjs": "^2.0.8", - "lucide-react": "^0.577.0", - "react": "^18.3.1", - "react-chartjs-2": "^5.2.0", - "react-dom": "^18.3.1" + "lucide-react": "^1.11.0", + "react": "^19.2.5", + "react-chartjs-2": "^5.3.1", + "react-dom": "^19.2.5" }, "devDependencies": { - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", - "concurrently": "^8.2.2", - "vite": "^6.0.0" + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "concurrently": "^9.2.1", + "vite": "^8.0.10" } } diff --git a/encodings/alp/src/alp/array.rs b/encodings/alp/src/alp/array.rs index caba6d60ec7..63549dc24f8 100644 --- a/encodings/alp/src/alp/array.rs +++ b/encodings/alp/src/alp/array.rs @@ -160,7 +160,7 @@ impl VTable for ALP { }) .transpose()?; - let slots = ALPData::make_slots(&encoded, &patches); + let slots = ALPData::make_slots(&encoded, patches.as_ref()); let data = ALPData::new( Exponents { e: u8::try_from(metadata.exp_e)?, @@ -371,7 +371,7 @@ impl ALP { pub fn new(encoded: ArrayRef, exponents: Exponents, patches: Option) -> ALPArray { let dtype = ALPData::logical_dtype(&encoded).vortex_expect("ALP encoded dtype"); let len = encoded.len(); - let slots = ALPData::make_slots(&encoded, &patches); + let slots = ALPData::make_slots(&encoded, patches.as_ref()); unsafe { Array::from_parts_unchecked( ArrayParts::new(ALP, dtype, len, ALPData::new(exponents, patches)) @@ -387,7 +387,7 @@ impl ALP { ) -> VortexResult { let dtype = ALPData::logical_dtype(&encoded)?; let len = encoded.len(); - let slots = ALPData::make_slots(&encoded, &patches); + let slots = ALPData::make_slots(&encoded, patches.as_ref()); let data = ALPData::new(exponents, patches); Array::try_from_parts(ArrayParts::new(ALP, dtype, len, data).with_slots(slots)) } @@ -401,7 +401,7 @@ impl ALP { ) -> ALPArray { let dtype = ALPData::logical_dtype(&encoded).vortex_expect("ALP encoded dtype"); let len = encoded.len(); - let slots = ALPData::make_slots(&encoded, &patches); + let slots = ALPData::make_slots(&encoded, patches.as_ref()); let data = unsafe { ALPData::new_unchecked(exponents, patches) }; unsafe { Array::from_parts_unchecked(ArrayParts::new(ALP, dtype, len, data).with_slots(slots)) @@ -410,7 +410,7 @@ impl ALP { } impl ALPData { - fn make_slots(encoded: &ArrayRef, patches: &Option) -> Vec> { + fn make_slots(encoded: &ArrayRef, patches: Option<&Patches>) -> Vec> { let (patch_indices, patch_values, patch_chunk_offsets) = match patches { Some(p) => ( Some(p.indices().clone()), diff --git a/encodings/alp/src/alp_rd/array.rs b/encodings/alp/src/alp_rd/array.rs index 17742168f83..0c25717db6f 100644 --- a/encodings/alp/src/alp_rd/array.rs +++ b/encodings/alp/src/alp_rd/array.rs @@ -221,7 +221,7 @@ impl VTable for ALPRD { left_parts_patches, &mut LEGACY_SESSION.create_execution_ctx(), )?; - let slots = ALPRDData::make_slots(&left_parts, &right_parts, &left_parts_patches); + let slots = ALPRDData::make_slots(&left_parts, &right_parts, left_parts_patches.as_ref()); let data = ALPRDData::new( left_parts_dictionary, u8::try_from(metadata.right_bit_width).map_err(|_| { @@ -383,7 +383,7 @@ impl ALPRD { let len = left_parts.len(); let left_parts_patches = ALPRDData::canonicalize_patches(&left_parts, left_parts_patches, ctx)?; - let slots = ALPRDData::make_slots(&left_parts, &right_parts, &left_parts_patches); + let slots = ALPRDData::make_slots(&left_parts, &right_parts, left_parts_patches.as_ref()); let data = ALPRDData::new(left_parts_dictionary, right_bit_width, left_parts_patches); Array::try_from_parts(ArrayParts::new(ALPRD, dtype, len, data).with_slots(slots)) } @@ -399,7 +399,7 @@ impl ALPRD { left_parts_patches: Option, ) -> ALPRDArray { let len = left_parts.len(); - let slots = ALPRDData::make_slots(&left_parts, &right_parts, &left_parts_patches); + let slots = ALPRDData::make_slots(&left_parts, &right_parts, left_parts_patches.as_ref()); let data = unsafe { ALPRDData::new_unchecked(left_parts_dictionary, right_bit_width, left_parts_patches) }; @@ -464,7 +464,7 @@ impl ALPRDData { fn make_slots( left_parts: &ArrayRef, right_parts: &ArrayRef, - patches: &Option, + patches: Option<&Patches>, ) -> Vec> { let (pi, pv, pco) = match patches { Some(p) => ( diff --git a/encodings/fastlanes/benches/compute_between.rs b/encodings/fastlanes/benches/compute_between.rs index 945dd9f0d5c..1630764ff8e 100644 --- a/encodings/fastlanes/benches/compute_between.rs +++ b/encodings/fastlanes/benches/compute_between.rs @@ -83,51 +83,11 @@ mod primitive { use vortex_array::dtype::NativePType; use vortex_array::scalar_fn::fns::between::BetweenOptions; use vortex_array::scalar_fn::fns::between::StrictComparison::NonStrict; - use vortex_array::scalar_fn::fns::operators::Operator; use vortex_error::VortexExpect; use crate::BENCH_ARGS; use crate::generate_primitive_array; - #[divan::bench( - types = [i32, i64, u32, u64, f32, f64], - args = BENCH_ARGS, - )] - fn old_raw_prim_test_between(bencher: Bencher, len: usize) - where - T: NumCast + NativePType, - vortex_array::scalar::Scalar: From, - { - let min = T::from_usize(5561).vortex_expect(""); - let max = T::from_usize(6032).vortex_expect(""); - let mut rng = StdRng::seed_from_u64(0); - let arr = generate_primitive_array::(&mut rng, len); - - bencher - .with_inputs(|| (&arr, LEGACY_SESSION.create_execution_ctx())) - .bench_refs(|(arr, ctx)| { - let gte = arr - .clone() - .into_array() - .binary( - ConstantArray::new(min, arr.len()).into_array(), - Operator::Gte, - ) - .vortex_expect(""); - let lt = arr - .clone() - .into_array() - .binary( - ConstantArray::new(max, arr.len()).into_array(), - Operator::Lt, - ) - .vortex_expect(""); - gte.binary(lt, Operator::And) - .vortex_expect("") - .execute::(ctx) - }) - } - #[divan::bench( types = [i32, i64, u32, u64, f32, f64], args = BENCH_ARGS, @@ -176,50 +136,11 @@ mod bitpack { use vortex_array::dtype::NativePType; use vortex_array::scalar_fn::fns::between::BetweenOptions; use vortex_array::scalar_fn::fns::between::StrictComparison::NonStrict; - use vortex_array::scalar_fn::fns::operators::Operator; use vortex_error::VortexExpect; use crate::BENCH_ARGS; use crate::generate_bit_pack_primitive_array; - #[divan::bench( - types = [i16, i32, i64], - args = BENCH_ARGS, - )] - fn old_bp_prim_test_between(bencher: Bencher, len: usize) - where - T: NumCast + NativePType, - vortex_array::scalar::Scalar: From, - { - let min = T::from_usize(5561).vortex_expect(""); - let max = T::from_usize(6032).vortex_expect(""); - let mut rng = StdRng::seed_from_u64(0); - let arr = generate_bit_pack_primitive_array::(&mut rng, len); - - bencher - .with_inputs(|| (&arr, LEGACY_SESSION.create_execution_ctx())) - .bench_refs(|(arr, ctx)| { - let gte = arr - .clone() - .binary( - ConstantArray::new(min, arr.len()).into_array(), - Operator::Gte, - ) - .vortex_expect(""); - let lt = arr - .clone() - .binary( - ConstantArray::new(max, arr.len()).into_array(), - Operator::Lt, - ) - .vortex_expect(""); - gte.binary(lt, Operator::And) - .unwrap() - .execute::(ctx) - .unwrap() - }) - } - #[divan::bench( types = [i16, i32, i64], args = BENCH_ARGS, @@ -267,50 +188,11 @@ mod alp { use vortex_array::dtype::NativePType; use vortex_array::scalar_fn::fns::between::BetweenOptions; use vortex_array::scalar_fn::fns::between::StrictComparison::NonStrict; - use vortex_array::scalar_fn::fns::operators::Operator; use vortex_error::VortexExpect; use crate::BENCH_ARGS; use crate::generate_alp_bit_pack_primitive_array; - #[divan::bench( - types = [f32, f64], - args = BENCH_ARGS, - )] - fn old_alp_prim_test_between(bencher: Bencher, len: usize) - where - T: NumCast + NativePType, - vortex_array::scalar::Scalar: From, - { - let min = T::from_usize(5561).vortex_expect(""); - let max = T::from_usize(6032).vortex_expect(""); - let mut rng = StdRng::seed_from_u64(0); - let arr = generate_alp_bit_pack_primitive_array::(&mut rng, len); - - bencher - .with_inputs(|| (&arr, LEGACY_SESSION.create_execution_ctx())) - .bench_refs(|(arr, ctx)| { - let gte = arr - .clone() - .binary( - ConstantArray::new(min, arr.len()).into_array(), - Operator::Gte, - ) - .vortex_expect(""); - let lt = arr - .clone() - .binary( - ConstantArray::new(max, arr.len()).into_array(), - Operator::Lt, - ) - .vortex_expect(""); - gte.binary(lt, Operator::And) - .unwrap() - .execute::(ctx) - .unwrap() - }) - } - #[divan::bench( types = [f32, f64], args = BENCH_ARGS, diff --git a/encodings/parquet-variant/src/operations.rs b/encodings/parquet-variant/src/operations.rs index 8a323cce76f..e812e0fcafa 100644 --- a/encodings/parquet-variant/src/operations.rs +++ b/encodings/parquet-variant/src/operations.rs @@ -214,7 +214,7 @@ fn scalar_from_shredded_object_scalar( let fields = StructFields::new(FieldNames::from(names), dtypes); Scalar::try_new( DType::Struct(fields, Nullability::NonNullable), - Some(ScalarValue::List(field_values)), + Some(ScalarValue::Tuple(field_values)), ) } @@ -330,7 +330,7 @@ fn parquet_variant_to_scalar(variant: PqVariant<'_, '_>) -> VortexResult let fields = StructFields::new(FieldNames::from(names), dtypes); Scalar::try_new( DType::Struct(fields, nn), - Some(ScalarValue::List(field_values)), + Some(ScalarValue::Tuple(field_values)), )? } }) diff --git a/encodings/sparse/src/canonical.rs b/encodings/sparse/src/canonical.rs index 0dcd8d533b1..8a27e72aed4 100644 --- a/encodings/sparse/src/canonical.rs +++ b/encodings/sparse/src/canonical.rs @@ -214,7 +214,7 @@ fn execute_sparse_lists_inner( } else { // Set with the fill value. builder - .append_value(fill_value.clone()) + .append_value(fill_value) .vortex_expect("Failed to append fill value"); } } diff --git a/fuzz/src/array/mod.rs b/fuzz/src/array/mod.rs index c75eeb309f2..8f2a5cd0fe6 100644 --- a/fuzz/src/array/mod.rs +++ b/fuzz/src/array/mod.rs @@ -657,7 +657,7 @@ pub fn run_fuzz_action(fuzz_action: FuzzArrayAction) -> VortexFuzzResult { Action::MinMax => { let min_max_result = min_max(¤t_array, &mut ctx) .vortex_expect("min_max operation should succeed in fuzz test"); - assert_min_max_eq(&expected.min_max(), &min_max_result, i)?; + assert_min_max_eq(expected.min_max().as_ref(), min_max_result.as_ref(), i)?; } Action::FillNull(fill_value) => { current_array = current_array @@ -770,14 +770,14 @@ pub fn assert_scalar_eq(lhs: &Scalar, rhs: &Scalar, step: usize) -> VortexFuzzRe /// Assert two min/max results are equal. #[expect(clippy::result_large_err)] pub fn assert_min_max_eq( - lhs: &Option, - rhs: &Option, + lhs: Option<&MinMaxResult>, + rhs: Option<&MinMaxResult>, step: usize, ) -> VortexFuzzResult<()> { if lhs != rhs { return Err(VortexFuzzError::MinMaxMismatch( - lhs.clone(), - rhs.clone(), + lhs.cloned(), + rhs.cloned(), step, Backtrace::capture(), )); diff --git a/java/testfiles/Cargo.lock b/java/testfiles/Cargo.lock index e3fe6731a30..29e7e0d2f4e 100644 --- a/java/testfiles/Cargo.lock +++ b/java/testfiles/Cargo.lock @@ -2399,6 +2399,7 @@ dependencies = [ "vortex-io", "vortex-mask", "vortex-metrics", + "vortex-runend", "vortex-scan", "vortex-sequence", "vortex-session", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index cb6bd203288..dbcc5a2f04e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "1.91.0" components = ["rust-src", "rustfmt", "clippy", "rust-analyzer"] -profile = "minimal" \ No newline at end of file +profile = "minimal" diff --git a/uv.lock b/uv.lock index b2e234fc1c3..1c06ece4294 100644 --- a/uv.lock +++ b/uv.lock @@ -1260,7 +1260,7 @@ wheels = [ [[package]] name = "ray" -version = "2.54.0" +version = "2.55.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -1273,17 +1273,20 @@ dependencies = [ { name = "requests" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/08/58/6209b2231947f3c8df09ce1436f1c76c4a11fcafd57c8def852dcbb6d8ef/ray-2.54.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8e39dd56b47a0a1820d5a5a54385bbe54d1d67e1093736d12d8ed4e99d0fa455", size = 70098998, upload-time = "2026-02-18T04:04:58.801Z" }, - { url = "https://files.pythonhosted.org/packages/ac/29/7871f4206e6b00a9bb784c16dad32ccd01e9df5a93545db92de220eb2871/ray-2.54.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:491ae56ab80d8822c4eaf4d5bb96dcf32a6231d8d7b76eb8034400eb9be1bb18", size = 72066630, upload-time = "2026-02-18T04:05:04.957Z" }, - { url = "https://files.pythonhosted.org/packages/1d/e8/d2c8ebd9cd945abc817b01ad02a29df78cdb86cd07d764587e16977389d0/ray-2.54.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:928bb09245a3c6f7c3c113ba8eafc69f948da9602d7f33e8251ecdf97c157615", size = 72895723, upload-time = "2026-02-18T04:05:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/7e/96/a5ea3a149a943475cda1d68fdcdb14c86251826c652c232ae853600ad7e7/ray-2.54.0-cp311-cp311-win_amd64.whl", hash = "sha256:1e786330de55b3ba2228e36ec305381a9b86f0b01a8b6072c5811c3bc4dd9a3d", size = 27448371, upload-time = "2026-02-18T04:05:16.34Z" }, - { url = "https://files.pythonhosted.org/packages/0e/16/45eefb51eb1767342a6dbf41af0b432279e422e56160705fcd1098a7ec53/ray-2.54.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:cf5c33b4b13850ec24a5bd5f9d9e0a8161f8e586bfd297e52913d170dec447fe", size = 70084880, upload-time = "2026-02-18T04:05:22.007Z" }, - { url = "https://files.pythonhosted.org/packages/60/ad/e07aca3637e9c3ec4857ec4366208099cf8488ece8061a9925ba29b66382/ray-2.54.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:795ae21d6b764245d3f521bc5833446d58569e7dfde9c5777417eb285d87450f", size = 72107346, upload-time = "2026-02-18T04:05:27.999Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b9/cc5ea8460c3dc602e6b7198277a7c59ba2b8929374ab22efa8df9f3deac8/ray-2.54.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:a972afd5aa3dda99d0b2f369b5f62e5dd95865ab7d37bf2e0a0e0d2cfbd9b325", size = 72967230, upload-time = "2026-02-18T04:05:33.771Z" }, - { url = "https://files.pythonhosted.org/packages/de/d7/744de3b1bb881701330ddcbb2f6efaccd65915d564ece899a3838f9fb105/ray-2.54.0-cp312-cp312-win_amd64.whl", hash = "sha256:2ee074ede491d0aacfa339c003f5d7a15826e1e2a72ce873234ccbc0446e19b3", size = 27427353, upload-time = "2026-02-18T04:05:38.853Z" }, - { url = "https://files.pythonhosted.org/packages/7f/f2/5c0161d10445e703b7d01413ab54ec1cc5e27032555279d296df89b9c4ee/ray-2.54.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5ad77961fea16c697a0fb0e51216dd39c0bec28868cde54ac668edd58d12b8ae", size = 70030991, upload-time = "2026-02-18T04:05:43.966Z" }, - { url = "https://files.pythonhosted.org/packages/fd/8c/4a4a38eaec6e9614076a96967f58540f4f8d4aa0c793f43150c5df23cb9a/ray-2.54.0-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:8952c23a8aa94f10728c2d16e0dc3732d09aa0e6254801757ff494984a214f45", size = 72013826, upload-time = "2026-02-18T04:05:49.866Z" }, - { url = "https://files.pythonhosted.org/packages/42/ac/e7ec2a406bd755f61c7090460fa5ab3f09b00c3c2d8db6d0b559f78a30eb/ray-2.54.0-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:ab89e6089abb6e46fb98fdd96d399b31a852d79127cd8ac00746c61d93defa2c", size = 72880209, upload-time = "2026-02-18T04:05:55.498Z" }, + { url = "https://files.pythonhosted.org/packages/88/7d/48ba2f49b40a34b0071ee27c0144a2573d8836094eaca213d59cef12c271/ray-2.55.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0053fd5b400f7ac56263aa1bbd3d68fb79341b08b8dc697c88782d5aca7b3ed4", size = 65835271, upload-time = "2026-04-22T20:09:34.984Z" }, + { url = "https://files.pythonhosted.org/packages/8f/a3/d6db3a428e4ea17cc72e79f747cfe11e90e63e36e1705bb8324e45f334b7/ray-2.55.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:0ea2f670a7725833ad2333a8c46ab69865ad06c8e5de9f65695e0f8f35331cec", size = 72879783, upload-time = "2026-04-22T20:09:40.986Z" }, + { url = "https://files.pythonhosted.org/packages/46/59/41da0e72a59cd3e8978480ccfeb86ef4235ae5ceb9b8928168a764fa930a/ray-2.55.1-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:d5382da181c03ee2f502ef46cf0ae4bbc30157b5bd9a67d7651f6a272528a85a", size = 73706515, upload-time = "2026-04-22T20:09:47.079Z" }, + { url = "https://files.pythonhosted.org/packages/65/52/c16bbdc3e31a5178f97be88966ab56db6f7e04882640c5cf2fee5b87757b/ray-2.55.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e56d2e8f304cafe990c198a2b894f5b813de018998cd7212869201f6dc17cff", size = 27882093, upload-time = "2026-04-22T20:09:52.943Z" }, + { url = "https://files.pythonhosted.org/packages/ac/3a/4d34f471a68b958b7f94c974c19ad6836a61a2dc16393df4294169a2e4b0/ray-2.55.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:137f9006eee28caab8260803cca314f37bbda3fc94fdfa31c770b5d019626ad8", size = 65822379, upload-time = "2026-04-22T20:09:58.064Z" }, + { url = "https://files.pythonhosted.org/packages/f1/13/0db535102d0256b350ca116d8987588aca1a1f9ebb4638e1e1ff88bbcef8/ray-2.55.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:26541f69bb55607ef8335baac75b2ed12ff2ce02d56313219b29eda003039221", size = 72910802, upload-time = "2026-04-22T20:10:04.382Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f8/fffadf3f4285eebd460e4d7f2ed1c0cd641ed89613c3f49eb881ee9fa7e2/ray-2.55.1-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:263705f6bab29e7622a94f82da25fd7f9cead76cdf89a07aab28f79cdf8f9d95", size = 73765203, upload-time = "2026-04-22T20:10:10.495Z" }, + { url = "https://files.pythonhosted.org/packages/10/f7/5acb86fc9625a0e6bbc40e1c7d42c60770e78585439a921c32738b6d675a/ray-2.55.1-cp312-cp312-win_amd64.whl", hash = "sha256:9ad56704c8bd7e92130162f9c58e4ef473609515637673d5a36e761f95335206", size = 27865547, upload-time = "2026-04-22T20:10:15.364Z" }, + { url = "https://files.pythonhosted.org/packages/d5/95/898699cc1a6a5f304ea95376d079843b5c05f4c8c1ec7e55a5cc7ffcea50/ray-2.55.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:f9844a9272ef2e6eb5771025866072cf4234cf4c7cc1a31e235b7de7111864be", size = 65766823, upload-time = "2026-04-22T20:10:20.786Z" }, + { url = "https://files.pythonhosted.org/packages/c9/13/87deecc090c672e45a0cf6f5eef511de448b93f37ef18fd10eb8e8557a0d/ray-2.55.1-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:b415d590e062f248907e0fe42994943f11726b7178fcf4b1cf5546721fb1a5f8", size = 72818676, upload-time = "2026-04-22T20:10:26.705Z" }, + { url = "https://files.pythonhosted.org/packages/71/d7/fc95d3b8824c62105c64aa1b59c59600b581f608d78a2af753e010936dc9/ray-2.55.1-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:1380e043eb57cde69b7e9199c6f2558ceeb8f0fc41c97d1d5e50ea042115f302", size = 73678908, upload-time = "2026-04-22T20:10:32.795Z" }, + { url = "https://files.pythonhosted.org/packages/a9/03/7e552325572e067b23a4584bda8dc6a67af8bd7e03c424d2610bfa93112d/ray-2.55.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:b062045c64c2bce39a51661624f7292c7bbf30f2a9d878627aae31d46da5712d", size = 65774106, upload-time = "2026-04-22T20:10:39.885Z" }, + { url = "https://files.pythonhosted.org/packages/94/62/607a8859520ce350861425f11f8e15d66c15ee33e6aac812f9e2889b5df4/ray-2.55.1-cp314-cp314-manylinux2014_aarch64.whl", hash = "sha256:4e618d61e1b14b6fde9a586151f3fd9d435b0b85048b997bcaa7f4a533747b2b", size = 72814044, upload-time = "2026-04-22T20:10:46.985Z" }, + { url = "https://files.pythonhosted.org/packages/04/5a/0699bef04a72d7dc54462960d07ef7a19cd8b1e09979880aba2b6d13cca2/ray-2.55.1-cp314-cp314-manylinux2014_x86_64.whl", hash = "sha256:156ed3e72ad95b645d2006cd71a8dddbcc89b56bfc00027f6225adf78bd9cb74", size = 73644244, upload-time = "2026-04-22T20:10:52.973Z" }, ] [[package]] diff --git a/vortex-array/public-api.lock b/vortex-array/public-api.lock index 2f36c30a472..0675fa157ad 100644 --- a/vortex-array/public-api.lock +++ b/vortex-array/public-api.lock @@ -30,6 +30,146 @@ pub fn vortex_array::arrays::PrimitiveArray::with_iterator(&self, f: F) -> pub mod vortex_array::aggregate_fn +pub mod vortex_array::aggregate_fn::combined + +pub struct vortex_array::aggregate_fn::combined::Combined(pub T) + +impl vortex_array::aggregate_fn::combined::Combined + +pub fn vortex_array::aggregate_fn::combined::Combined::new(inner: T) -> Self + +impl core::clone::Clone for vortex_array::aggregate_fn::combined::Combined + +pub fn vortex_array::aggregate_fn::combined::Combined::clone(&self) -> vortex_array::aggregate_fn::combined::Combined + +impl core::fmt::Debug for vortex_array::aggregate_fn::combined::Combined + +pub fn vortex_array::aggregate_fn::combined::Combined::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::combined::Combined + +pub type vortex_array::aggregate_fn::combined::Combined::Options = vortex_array::aggregate_fn::combined::PairOptions<<::Left as vortex_array::aggregate_fn::AggregateFnVTable>::Options, <::Right as vortex_array::aggregate_fn::AggregateFnVTable>::Options> + +pub type vortex_array::aggregate_fn::combined::Combined::Partial = (<::Left as vortex_array::aggregate_fn::AggregateFnVTable>::Partial, <::Right as vortex_array::aggregate_fn::AggregateFnVTable>::Partial) + +pub fn vortex_array::aggregate_fn::combined::Combined::accumulate(&self, _state: &mut Self::Partial, _batch: &vortex_array::Columnar, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::combined::Combined::coerce_args(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::combine_partials(&self, partial: &mut Self::Partial, other: vortex_array::scalar::Scalar) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::combined::Combined::deserialize(&self, metadata: &[u8], session: &vortex_session::VortexSession) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::empty_partial(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::finalize(&self, states: vortex_array::ArrayRef) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::id(&self) -> vortex_array::aggregate_fn::AggregateFnId + +pub fn vortex_array::aggregate_fn::combined::Combined::is_saturated(&self, partial: &Self::Partial) -> bool + +pub fn vortex_array::aggregate_fn::combined::Combined::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::combined::Combined::reset(&self, partial: &mut Self::Partial) + +pub fn vortex_array::aggregate_fn::combined::Combined::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::combined::Combined::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> + +pub fn vortex_array::aggregate_fn::combined::Combined::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::try_accumulate(&self, state: &mut Self::Partial, batch: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult + +pub struct vortex_array::aggregate_fn::combined::PairOptions(pub L, pub R) + +impl core::marker::StructuralPartialEq for vortex_array::aggregate_fn::combined::PairOptions + +impl core::clone::Clone for vortex_array::aggregate_fn::combined::PairOptions + +pub fn vortex_array::aggregate_fn::combined::PairOptions::clone(&self) -> vortex_array::aggregate_fn::combined::PairOptions + +impl core::cmp::Eq for vortex_array::aggregate_fn::combined::PairOptions + +impl core::cmp::PartialEq for vortex_array::aggregate_fn::combined::PairOptions + +pub fn vortex_array::aggregate_fn::combined::PairOptions::eq(&self, other: &vortex_array::aggregate_fn::combined::PairOptions) -> bool + +impl core::fmt::Debug for vortex_array::aggregate_fn::combined::PairOptions + +pub fn vortex_array::aggregate_fn::combined::PairOptions::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +impl core::fmt::Display for vortex_array::aggregate_fn::combined::PairOptions + +pub fn vortex_array::aggregate_fn::combined::PairOptions::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +impl core::hash::Hash for vortex_array::aggregate_fn::combined::PairOptions + +pub fn vortex_array::aggregate_fn::combined::PairOptions::hash<__H: core::hash::Hasher>(&self, state: &mut __H) + +pub trait vortex_array::aggregate_fn::combined::BinaryCombined: 'static + core::marker::Send + core::marker::Sync + core::clone::Clone + +pub type vortex_array::aggregate_fn::combined::BinaryCombined::Left: vortex_array::aggregate_fn::AggregateFnVTable + +pub type vortex_array::aggregate_fn::combined::BinaryCombined::Right: vortex_array::aggregate_fn::AggregateFnVTable + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::coerce_args(&self, options: &vortex_array::aggregate_fn::combined::CombinedOptions, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::deserialize(&self, metadata: &[u8], session: &vortex_session::VortexSession) -> vortex_error::VortexResult> + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::finalize(&self, left: vortex_array::ArrayRef, right: vortex_array::ArrayRef) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::finalize_scalar(&self, left_scalar: vortex_array::scalar::Scalar, right_scalar: vortex_array::scalar::Scalar) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::id(&self) -> vortex_array::aggregate_fn::AggregateFnId + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::left(&self) -> Self::Left + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::left_name(&self) -> &'static str + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::partial_struct_dtype(&self, left: vortex_array::dtype::DType, right: vortex_array::dtype::DType) -> vortex_array::dtype::DType + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::return_dtype(&self, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::right(&self) -> Self::Right + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::right_name(&self) -> &'static str + +pub fn vortex_array::aggregate_fn::combined::BinaryCombined::serialize(&self, options: &vortex_array::aggregate_fn::combined::CombinedOptions) -> vortex_error::VortexResult>> + +impl vortex_array::aggregate_fn::combined::BinaryCombined for vortex_array::aggregate_fn::fns::mean::Mean + +pub type vortex_array::aggregate_fn::fns::mean::Mean::Left = vortex_array::aggregate_fn::fns::sum::Sum + +pub type vortex_array::aggregate_fn::fns::mean::Mean::Right = vortex_array::aggregate_fn::fns::count::Count + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::coerce_args(&self, _options: &vortex_array::aggregate_fn::combined::PairOptions<::Options, ::Options>, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::deserialize(&self, metadata: &[u8], session: &vortex_session::VortexSession) -> vortex_error::VortexResult> + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::finalize(&self, sum: vortex_array::ArrayRef, count: vortex_array::ArrayRef) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::finalize_scalar(&self, left_scalar: vortex_array::scalar::Scalar, right_scalar: vortex_array::scalar::Scalar) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::id(&self) -> vortex_array::aggregate_fn::AggregateFnId + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::left(&self) -> vortex_array::aggregate_fn::fns::sum::Sum + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::left_name(&self) -> &'static str + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::partial_struct_dtype(&self, left: vortex_array::dtype::DType, right: vortex_array::dtype::DType) -> vortex_array::dtype::DType + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::return_dtype(&self, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::right(&self) -> vortex_array::aggregate_fn::fns::count::Count + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::right_name(&self) -> &'static str + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::serialize(&self, _options: &vortex_array::aggregate_fn::combined::CombinedOptions) -> vortex_error::VortexResult>> + +pub type vortex_array::aggregate_fn::combined::CombinedOptions = vortex_array::aggregate_fn::combined::PairOptions<<::Left as vortex_array::aggregate_fn::AggregateFnVTable>::Options, <::Right as vortex_array::aggregate_fn::AggregateFnVTable>::Options> + pub mod vortex_array::aggregate_fn::fns pub mod vortex_array::aggregate_fn::fns::count @@ -344,6 +484,54 @@ pub struct vortex_array::aggregate_fn::fns::last::LastPartial pub fn vortex_array::aggregate_fn::fns::last::last(array: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub mod vortex_array::aggregate_fn::fns::mean + +pub struct vortex_array::aggregate_fn::fns::mean::Mean + +impl vortex_array::aggregate_fn::fns::mean::Mean + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::combined() -> vortex_array::aggregate_fn::combined::Combined + +impl core::clone::Clone for vortex_array::aggregate_fn::fns::mean::Mean + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::clone(&self) -> vortex_array::aggregate_fn::fns::mean::Mean + +impl core::fmt::Debug for vortex_array::aggregate_fn::fns::mean::Mean + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +impl vortex_array::aggregate_fn::combined::BinaryCombined for vortex_array::aggregate_fn::fns::mean::Mean + +pub type vortex_array::aggregate_fn::fns::mean::Mean::Left = vortex_array::aggregate_fn::fns::sum::Sum + +pub type vortex_array::aggregate_fn::fns::mean::Mean::Right = vortex_array::aggregate_fn::fns::count::Count + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::coerce_args(&self, _options: &vortex_array::aggregate_fn::combined::PairOptions<::Options, ::Options>, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::deserialize(&self, metadata: &[u8], session: &vortex_session::VortexSession) -> vortex_error::VortexResult> + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::finalize(&self, sum: vortex_array::ArrayRef, count: vortex_array::ArrayRef) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::finalize_scalar(&self, left_scalar: vortex_array::scalar::Scalar, right_scalar: vortex_array::scalar::Scalar) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::id(&self) -> vortex_array::aggregate_fn::AggregateFnId + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::left(&self) -> vortex_array::aggregate_fn::fns::sum::Sum + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::left_name(&self) -> &'static str + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::partial_struct_dtype(&self, left: vortex_array::dtype::DType, right: vortex_array::dtype::DType) -> vortex_array::dtype::DType + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::return_dtype(&self, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::right(&self) -> vortex_array::aggregate_fn::fns::count::Count + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::right_name(&self) -> &'static str + +pub fn vortex_array::aggregate_fn::fns::mean::Mean::serialize(&self, _options: &vortex_array::aggregate_fn::combined::CombinedOptions) -> vortex_error::VortexResult>> + +pub fn vortex_array::aggregate_fn::fns::mean::mean(array: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult + pub mod vortex_array::aggregate_fn::fns::min_max pub struct vortex_array::aggregate_fn::fns::min_max::MinMax @@ -574,6 +762,12 @@ impl core::fmt::Debug for vortex_array::aggregate_fn::session::AggregateFnSessio pub fn vortex_array::aggregate_fn::session::AggregateFnSession::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_array::aggregate_fn::session::AggregateFnSession + +pub fn vortex_array::aggregate_fn::session::AggregateFnSession::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_array::aggregate_fn::session::AggregateFnSession::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub trait vortex_array::aggregate_fn::session::AggregateFnSessionExt: vortex_session::SessionExt pub fn vortex_array::aggregate_fn::session::AggregateFnSessionExt::aggregate_fns(&self) -> vortex_session::Ref<'_, vortex_array::aggregate_fn::session::AggregateFnSession> @@ -1070,6 +1264,42 @@ pub fn vortex_array::aggregate_fn::fns::sum::Sum::to_scalar(&self, partial: &Sel pub fn vortex_array::aggregate_fn::fns::sum::Sum::try_accumulate(&self, _state: &mut Self::Partial, _batch: &vortex_array::ArrayRef, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::combined::Combined + +pub type vortex_array::aggregate_fn::combined::Combined::Options = vortex_array::aggregate_fn::combined::PairOptions<<::Left as vortex_array::aggregate_fn::AggregateFnVTable>::Options, <::Right as vortex_array::aggregate_fn::AggregateFnVTable>::Options> + +pub type vortex_array::aggregate_fn::combined::Combined::Partial = (<::Left as vortex_array::aggregate_fn::AggregateFnVTable>::Partial, <::Right as vortex_array::aggregate_fn::AggregateFnVTable>::Partial) + +pub fn vortex_array::aggregate_fn::combined::Combined::accumulate(&self, _state: &mut Self::Partial, _batch: &vortex_array::Columnar, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::combined::Combined::coerce_args(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::combine_partials(&self, partial: &mut Self::Partial, other: vortex_array::scalar::Scalar) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::combined::Combined::deserialize(&self, metadata: &[u8], session: &vortex_session::VortexSession) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::empty_partial(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::finalize(&self, states: vortex_array::ArrayRef) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::id(&self) -> vortex_array::aggregate_fn::AggregateFnId + +pub fn vortex_array::aggregate_fn::combined::Combined::is_saturated(&self, partial: &Self::Partial) -> bool + +pub fn vortex_array::aggregate_fn::combined::Combined::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::combined::Combined::reset(&self, partial: &mut Self::Partial) + +pub fn vortex_array::aggregate_fn::combined::Combined::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::combined::Combined::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> + +pub fn vortex_array::aggregate_fn::combined::Combined::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::combined::Combined::try_accumulate(&self, state: &mut Self::Partial, batch: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult + pub trait vortex_array::aggregate_fn::AggregateFnVTableExt: vortex_array::aggregate_fn::AggregateFnVTable pub fn vortex_array::aggregate_fn::AggregateFnVTableExt::bind(&self, options: Self::Options) -> vortex_array::aggregate_fn::AggregateFnRef @@ -3178,23 +3408,51 @@ impl vortex_array::ArrayHash for vortex_array::arrays::masked::MaskedData pub fn vortex_array::arrays::masked::MaskedData::array_hash(&self, _state: &mut H, _precision: vortex_array::Precision) -pub trait vortex_array::arrays::masked::MaskedArrayExt: vortex_array::TypedArrayRef +pub struct vortex_array::arrays::masked::MaskedSlots -pub fn vortex_array::arrays::masked::MaskedArrayExt::child(&self) -> &vortex_array::ArrayRef +pub vortex_array::arrays::masked::MaskedSlots::child: vortex_array::ArrayRef -pub fn vortex_array::arrays::masked::MaskedArrayExt::masked_validity(&self) -> vortex_array::validity::Validity +pub vortex_array::arrays::masked::MaskedSlots::validity: core::option::Option + +impl vortex_array::arrays::masked::MaskedSlots + +pub const vortex_array::arrays::masked::MaskedSlots::CHILD: usize + +pub const vortex_array::arrays::masked::MaskedSlots::COUNT: usize + +pub const vortex_array::arrays::masked::MaskedSlots::NAMES: [&'static str; 2] + +pub const vortex_array::arrays::masked::MaskedSlots::VALIDITY: usize -pub fn vortex_array::arrays::masked::MaskedArrayExt::validity_child(&self) -> core::option::Option<&vortex_array::ArrayRef> +pub fn vortex_array::arrays::masked::MaskedSlots::from_slots(slots: alloc::vec::Vec>) -> Self + +pub fn vortex_array::arrays::masked::MaskedSlots::into_slots(self) -> alloc::vec::Vec> + +pub trait vortex_array::arrays::masked::MaskedArrayExt: vortex_array::TypedArrayRef + vortex_array::arrays::masked::MaskedArraySlotsExt + +pub fn vortex_array::arrays::masked::MaskedArrayExt::masked_validity(&self) -> vortex_array::validity::Validity impl> vortex_array::arrays::masked::MaskedArrayExt for T +pub fn T::masked_validity(&self) -> vortex_array::validity::Validity + +pub trait vortex_array::arrays::masked::MaskedArraySlotsExt: vortex_array::TypedArrayRef + +pub fn vortex_array::arrays::masked::MaskedArraySlotsExt::child(&self) -> &vortex_array::ArrayRef + +pub fn vortex_array::arrays::masked::MaskedArraySlotsExt::slots_view(&self) -> vortex_array::arrays::masked::array::MaskedSlotsView<'_> + +pub fn vortex_array::arrays::masked::MaskedArraySlotsExt::validity(&self) -> core::option::Option<&vortex_array::ArrayRef> + +impl> vortex_array::arrays::masked::MaskedArraySlotsExt for T + pub fn T::child(&self) -> &vortex_array::ArrayRef -pub fn T::masked_validity(&self) -> vortex_array::validity::Validity +pub fn T::slots_view(&self) -> vortex_array::arrays::masked::array::MaskedSlotsView<'_> -pub fn T::validity_child(&self) -> core::option::Option<&vortex_array::ArrayRef> +pub fn T::validity(&self) -> core::option::Option<&vortex_array::ArrayRef> -pub fn vortex_array::arrays::masked::mask_validity_canonical(canonical: vortex_array::Canonical, validity_mask: &vortex_mask::Mask, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult +pub fn vortex_array::arrays::masked::mask_validity_canonical(canonical: vortex_array::Canonical, validity: vortex_array::validity::Validity, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub type vortex_array::arrays::masked::MaskedArray = vortex_array::Array @@ -8820,6 +9078,12 @@ impl core::fmt::Debug for vortex_array::dtype::session::DTypeSession pub fn vortex_array::dtype::session::DTypeSession::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_array::dtype::session::DTypeSession + +pub fn vortex_array::dtype::session::DTypeSession::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_array::dtype::session::DTypeSession::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub trait vortex_array::dtype::session::DTypeSessionExt: vortex_session::SessionExt pub fn vortex_array::dtype::session::DTypeSessionExt::dtypes(&self) -> vortex_session::Ref<'_, vortex_array::dtype::session::DTypeSession> @@ -13150,6 +13414,12 @@ impl core::fmt::Debug for vortex_array::memory::MemorySession pub fn vortex_array::memory::MemorySession::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_array::memory::MemorySession + +pub fn vortex_array::memory::MemorySession::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_array::memory::MemorySession::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub struct vortex_array::memory::WritableHostBuffer impl vortex_array::memory::WritableHostBuffer @@ -13256,6 +13526,12 @@ impl core::fmt::Debug for vortex_array::optimizer::kernels::ArrayKernels pub fn vortex_array::optimizer::kernels::ArrayKernels::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_array::optimizer::kernels::ArrayKernels + +pub fn vortex_array::optimizer::kernels::ArrayKernels::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_array::optimizer::kernels::ArrayKernels::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub trait vortex_array::optimizer::kernels::ArrayKernelsExt: vortex_session::SessionExt pub fn vortex_array::optimizer::kernels::ArrayKernelsExt::kernels(&self) -> vortex_session::Ref<'_, vortex_array::optimizer::kernels::ArrayKernels> @@ -13960,10 +14236,10 @@ pub vortex_array::scalar::ScalarValue::Bool(bool) pub vortex_array::scalar::ScalarValue::Decimal(vortex_array::scalar::DecimalValue) -pub vortex_array::scalar::ScalarValue::List(alloc::vec::Vec>) - pub vortex_array::scalar::ScalarValue::Primitive(vortex_array::scalar::PValue) +pub vortex_array::scalar::ScalarValue::Tuple(alloc::vec::Vec>) + pub vortex_array::scalar::ScalarValue::Utf8(vortex_buffer::string::BufferString) pub vortex_array::scalar::ScalarValue::Variant(alloc::boxed::Box) @@ -14248,6 +14524,8 @@ impl<'a> core::hash::Hash for vortex_array::scalar::BinaryScalar<'a> pub fn vortex_array::scalar::BinaryScalar<'a>::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +impl<'a> core::marker::Copy for vortex_array::scalar::BinaryScalar<'a> + pub struct vortex_array::scalar::BoolScalar<'a> impl<'a> vortex_array::scalar::BoolScalar<'a> @@ -14298,6 +14576,8 @@ impl<'a> core::hash::Hash for vortex_array::scalar::BoolScalar<'a> pub fn vortex_array::scalar::BoolScalar<'a>::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +impl<'a> core::marker::Copy for vortex_array::scalar::BoolScalar<'a> + pub struct vortex_array::scalar::DecimalScalar<'a> impl<'a> vortex_array::scalar::DecimalScalar<'a> @@ -14464,6 +14744,8 @@ impl<'a> core::fmt::Debug for vortex_array::scalar::ExtScalar<'a> pub fn vortex_array::scalar::ExtScalar<'a>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl<'a> core::marker::Copy for vortex_array::scalar::ExtScalar<'a> + pub struct vortex_array::scalar::ListScalar<'a> impl<'a> vortex_array::scalar::ListScalar<'a> @@ -14516,6 +14798,8 @@ impl<'a> core::fmt::Debug for vortex_array::scalar::ListScalar<'a> pub fn vortex_array::scalar::ListScalar<'a>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl<'a> core::marker::Copy for vortex_array::scalar::ListScalar<'a> + pub struct vortex_array::scalar::PrimitiveScalar<'a> impl<'a> vortex_array::scalar::PrimitiveScalar<'a> @@ -15310,6 +15594,8 @@ impl<'a> core::fmt::Debug for vortex_array::scalar::StructScalar<'a> pub fn vortex_array::scalar::StructScalar<'a>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl<'a> core::marker::Copy for vortex_array::scalar::StructScalar<'a> + pub struct vortex_array::scalar::Utf8Scalar<'a> impl<'a> vortex_array::scalar::Utf8Scalar<'a> @@ -15360,6 +15646,8 @@ impl<'a> core::hash::Hash for vortex_array::scalar::Utf8Scalar<'a> pub fn vortex_array::scalar::Utf8Scalar<'a>::hash<__H: core::hash::Hasher>(&self, state: &mut __H) +impl<'a> core::marker::Copy for vortex_array::scalar::Utf8Scalar<'a> + pub struct vortex_array::scalar::VariantScalar<'a> impl<'a> vortex_array::scalar::VariantScalar<'a> @@ -17296,6 +17584,58 @@ pub trait vortex_array::scalar_fn::fns::zip::ZipReduce: vortex_array::VTable pub fn vortex_array::scalar_fn::fns::zip::ZipReduce::zip(array: vortex_array::ArrayView<'_, Self>, if_false: &vortex_array::ArrayRef, mask: &vortex_array::ArrayRef) -> vortex_error::VortexResult> +pub mod vortex_array::scalar_fn::internal + +pub mod vortex_array::scalar_fn::internal::row_count + +pub struct vortex_array::scalar_fn::internal::row_count::RowCount + +impl core::clone::Clone for vortex_array::scalar_fn::internal::row_count::RowCount + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::clone(&self) -> vortex_array::scalar_fn::internal::row_count::RowCount + +impl vortex_array::scalar_fn::ScalarFnVTable for vortex_array::scalar_fn::internal::row_count::RowCount + +pub type vortex_array::scalar_fn::internal::row_count::RowCount::Options = vortex_array::scalar_fn::EmptyOptions + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::arity(&self, _options: &Self::Options) -> vortex_array::scalar_fn::Arity + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::child_name(&self, _options: &Self::Options, _child_idx: usize) -> vortex_array::scalar_fn::ChildName + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::coerce_args(&self, options: &Self::Options, args: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::deserialize(&self, _metadata: &[u8], _session: &vortex_session::VortexSession) -> vortex_error::VortexResult + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::execute(&self, _options: &Self::Options, _args: &dyn vortex_array::scalar_fn::ExecutionArgs, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::fmt_sql(&self, _options: &Self::Options, _expr: &vortex_array::expr::Expression, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::id(&self) -> vortex_array::scalar_fn::ScalarFnId + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::is_fallible(&self, _options: &Self::Options) -> bool + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::is_null_sensitive(&self, _options: &Self::Options) -> bool + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::reduce(&self, options: &Self::Options, node: &dyn vortex_array::scalar_fn::ReduceNode, ctx: &dyn vortex_array::scalar_fn::ReduceCtx) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::return_dtype(&self, _options: &Self::Options, _args: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::simplify(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, ctx: &dyn vortex_array::scalar_fn::SimplifyCtx) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::simplify_untyped(&self, options: &Self::Options, expr: &vortex_array::expr::Expression) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::stat_expression(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, stat: vortex_array::expr::stats::Stat, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::stat_falsification(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::validity(&self, options: &Self::Options, expression: &vortex_array::expr::Expression) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::contains_row_count(array: &vortex_array::ArrayRef) -> bool + +pub fn vortex_array::scalar_fn::internal::row_count::substitute_row_count(array: vortex_array::ArrayRef, replacement: &vortex_array::ArrayRef) -> vortex_error::VortexResult + pub mod vortex_array::scalar_fn::session pub struct vortex_array::scalar_fn::session::ScalarFnSession @@ -17314,6 +17654,12 @@ impl core::fmt::Debug for vortex_array::scalar_fn::session::ScalarFnSession pub fn vortex_array::scalar_fn::session::ScalarFnSession::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_array::scalar_fn::session::ScalarFnSession + +pub fn vortex_array::scalar_fn::session::ScalarFnSession::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_array::scalar_fn::session::ScalarFnSession::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub trait vortex_array::scalar_fn::session::ScalarFnSessionExt: vortex_session::SessionExt pub fn vortex_array::scalar_fn::session::ScalarFnSessionExt::scalar_fns(&self) -> vortex_session::Ref<'_, vortex_array::scalar_fn::session::ScalarFnSession> @@ -18444,6 +18790,44 @@ pub fn vortex_array::scalar_fn::fns::zip::Zip::stat_falsification(&self, options pub fn vortex_array::scalar_fn::fns::zip::Zip::validity(&self, options: &Self::Options, expression: &vortex_array::expr::Expression) -> vortex_error::VortexResult> +impl vortex_array::scalar_fn::ScalarFnVTable for vortex_array::scalar_fn::internal::row_count::RowCount + +pub type vortex_array::scalar_fn::internal::row_count::RowCount::Options = vortex_array::scalar_fn::EmptyOptions + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::arity(&self, _options: &Self::Options) -> vortex_array::scalar_fn::Arity + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::child_name(&self, _options: &Self::Options, _child_idx: usize) -> vortex_array::scalar_fn::ChildName + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::coerce_args(&self, options: &Self::Options, args: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::deserialize(&self, _metadata: &[u8], _session: &vortex_session::VortexSession) -> vortex_error::VortexResult + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::execute(&self, _options: &Self::Options, _args: &dyn vortex_array::scalar_fn::ExecutionArgs, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::fmt_sql(&self, _options: &Self::Options, _expr: &vortex_array::expr::Expression, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::id(&self) -> vortex_array::scalar_fn::ScalarFnId + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::is_fallible(&self, _options: &Self::Options) -> bool + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::is_null_sensitive(&self, _options: &Self::Options) -> bool + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::reduce(&self, options: &Self::Options, node: &dyn vortex_array::scalar_fn::ReduceNode, ctx: &dyn vortex_array::scalar_fn::ReduceCtx) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::return_dtype(&self, _options: &Self::Options, _args: &[vortex_array::dtype::DType]) -> vortex_error::VortexResult + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::simplify(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, ctx: &dyn vortex_array::scalar_fn::SimplifyCtx) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::simplify_untyped(&self, options: &Self::Options, expr: &vortex_array::expr::Expression) -> vortex_error::VortexResult> + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::stat_expression(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, stat: vortex_array::expr::stats::Stat, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::stat_falsification(&self, options: &Self::Options, expr: &vortex_array::expr::Expression, catalog: &dyn vortex_array::expr::pruning::StatsCatalog) -> core::option::Option + +pub fn vortex_array::scalar_fn::internal::row_count::RowCount::validity(&self, options: &Self::Options, expression: &vortex_array::expr::Expression) -> vortex_error::VortexResult> + pub trait vortex_array::scalar_fn::ScalarFnVTableExt: vortex_array::scalar_fn::ScalarFnVTable pub fn vortex_array::scalar_fn::ScalarFnVTableExt::bind(&self, options: Self::Options) -> vortex_array::scalar_fn::ScalarFnRef @@ -18730,6 +19114,12 @@ impl core::fmt::Debug for vortex_array::session::ArraySession pub fn vortex_array::session::ArraySession::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_array::session::ArraySession + +pub fn vortex_array::session::ArraySession::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_array::session::ArraySession::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub trait vortex_array::session::ArraySessionExt: vortex_session::SessionExt pub fn vortex_array::session::ArraySessionExt::array_serialize(&self, array: &vortex_array::ArrayRef) -> vortex_error::VortexResult>> diff --git a/vortex-array/src/aggregate_fn/accumulator_grouped.rs b/vortex-array/src/aggregate_fn/accumulator_grouped.rs index 665dcec0747..a751a7c5749 100644 --- a/vortex-array/src/aggregate_fn/accumulator_grouped.rs +++ b/vortex-array/src/aggregate_fn/accumulator_grouped.rs @@ -311,7 +311,7 @@ impl GroupedAccumulator { if validity.value(i) { let group = elements.slice(offset..offset + size)?; accumulator.accumulate(&group, ctx)?; - states.append_scalar(&accumulator.finish()?)?; + states.append_scalar(&accumulator.flush()?)?; } else { states.append_null() } diff --git a/vortex-array/src/aggregate_fn/combined.rs b/vortex-array/src/aggregate_fn/combined.rs new file mode 100644 index 00000000000..ab0ebca5785 --- /dev/null +++ b/vortex-array/src/aggregate_fn/combined.rs @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Generic adapter for aggregates whose result is computed from two child +//! aggregate functions, e.g. `Mean = Sum / Count`. + +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use std::fmt::{self}; +use std::hash::Hash; + +use vortex_error::VortexResult; +use vortex_error::vortex_bail; +use vortex_error::vortex_err; +use vortex_session::VortexSession; + +use crate::ArrayRef; +use crate::Columnar; +use crate::ExecutionCtx; +use crate::aggregate_fn::AggregateFnId; +use crate::aggregate_fn::AggregateFnVTable; +use crate::builtins::ArrayBuiltins; +use crate::dtype::DType; +use crate::dtype::FieldName; +use crate::dtype::FieldNames; +use crate::dtype::Nullability; +use crate::dtype::StructFields; +use crate::scalar::Scalar; + +/// Pair of options for the two children of a [`BinaryCombined`] aggregate. +/// +/// Wrapper around `(L, R)` because the [`AggregateFnVTable::Options`] bound +/// requires `Display`, which tuples don't implement. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct PairOptions(pub L, pub R); + +impl Display for PairOptions { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "({}, {})", self.0, self.1) + } +} + +// Convenience aliases so signatures stay readable. +type LeftOptions = <::Left as AggregateFnVTable>::Options; +type RightOptions = <::Right as AggregateFnVTable>::Options; +type LeftPartial = <::Left as AggregateFnVTable>::Partial; +type RightPartial = <::Right as AggregateFnVTable>::Partial; +/// Combined options for a [`BinaryCombined`] aggregate. +pub type CombinedOptions = PairOptions, RightOptions>; + +/// Declare an aggregate function in terms of two child aggregates. +pub trait BinaryCombined: 'static + Send + Sync + Clone { + /// The left child aggregate vtable. + type Left: AggregateFnVTable; + /// The right child aggregate vtable. + type Right: AggregateFnVTable; + + /// Stable identifier for the combined aggregate. + fn id(&self) -> AggregateFnId; + + /// Construct the left child vtable. + fn left(&self) -> Self::Left; + + /// Construct the right child vtable. + fn right(&self) -> Self::Right; + + /// Field name for the left child in the partial struct dtype. + fn left_name(&self) -> &'static str { + "left" + } + + /// Field name for the right child in the partial struct dtype. + fn right_name(&self) -> &'static str { + "right" + } + + /// Return type of the combined aggregate. + fn return_dtype(&self, input_dtype: &DType) -> Option; + + /// Combine the finalized left and right results into the final aggregate. + fn finalize(&self, left: ArrayRef, right: ArrayRef) -> VortexResult; + + fn finalize_scalar(&self, left_scalar: Scalar, right_scalar: Scalar) -> VortexResult; + + /// Serialize the options for this combined aggregate. Default: not serializable. + fn serialize(&self, options: &CombinedOptions) -> VortexResult>> { + let _ = options; + Ok(None) + } + + /// Deserialize the options for this combined aggregate. Default: bails. + fn deserialize( + &self, + metadata: &[u8], + session: &VortexSession, + ) -> VortexResult> { + let _ = (metadata, session); + vortex_bail!( + "Combined aggregate function {} is not deserializable", + BinaryCombined::id(self) + ); + } + + /// Coerce the input type. Default: chains `right.coerce_args(left.coerce_args(input))`. + fn coerce_args( + &self, + options: &CombinedOptions, + input_dtype: &DType, + ) -> VortexResult { + let left_coerced = self.left().coerce_args(&options.0, input_dtype)?; + self.right().coerce_args(&options.1, &left_coerced) + } + + /// Build the partial struct dtype that wraps the two child partials. + fn partial_struct_dtype(&self, left: DType, right: DType) -> DType { + DType::Struct( + StructFields::new( + FieldNames::from_iter([ + FieldName::from(self.left_name()), + FieldName::from(self.right_name()), + ]), + vec![left, right], + ), + Nullability::NonNullable, + ) + } +} + +/// Adapter that exposes any [`BinaryCombined`] as an [`AggregateFnVTable`]. +#[derive(Clone, Debug)] +pub struct Combined(pub T); + +impl Combined { + /// Construct a new combined aggregate vtable. + pub fn new(inner: T) -> Self { + Self(inner) + } +} + +impl AggregateFnVTable for Combined { + type Options = CombinedOptions; + type Partial = (LeftPartial, RightPartial); + + fn id(&self) -> AggregateFnId { + self.0.id() + } + + fn serialize(&self, options: &Self::Options) -> VortexResult>> { + BinaryCombined::serialize(&self.0, options) + } + + fn deserialize(&self, metadata: &[u8], session: &VortexSession) -> VortexResult { + BinaryCombined::deserialize(&self.0, metadata, session) + } + + fn coerce_args(&self, options: &Self::Options, input_dtype: &DType) -> VortexResult { + BinaryCombined::coerce_args(&self.0, options, input_dtype) + } + + fn return_dtype(&self, _options: &Self::Options, input_dtype: &DType) -> Option { + BinaryCombined::return_dtype(&self.0, input_dtype) + } + + fn partial_dtype(&self, options: &Self::Options, input_dtype: &DType) -> Option { + let l = self.0.left().partial_dtype(&options.0, input_dtype)?; + let r = self.0.right().partial_dtype(&options.1, input_dtype)?; + Some(self.0.partial_struct_dtype(l, r)) + } + + fn empty_partial( + &self, + options: &Self::Options, + input_dtype: &DType, + ) -> VortexResult { + Ok(( + self.0.left().empty_partial(&options.0, input_dtype)?, + self.0.right().empty_partial(&options.1, input_dtype)?, + )) + } + + fn combine_partials(&self, partial: &mut Self::Partial, other: Scalar) -> VortexResult<()> { + if other.is_null() { + return Ok(()); + } + let s = other.as_struct(); + let lname = self.0.left_name(); + let rname = self.0.right_name(); + let l_field = s + .field(lname) + .ok_or_else(|| vortex_err!("BinaryCombined partial missing `{}` field", lname))?; + let r_field = s + .field(rname) + .ok_or_else(|| vortex_err!("BinaryCombined partial missing `{}` field", rname))?; + self.0.left().combine_partials(&mut partial.0, l_field)?; + self.0.right().combine_partials(&mut partial.1, r_field)?; + Ok(()) + } + + fn to_scalar(&self, partial: &Self::Partial) -> VortexResult { + let l_scalar = self.0.left().to_scalar(&partial.0)?; + let r_scalar = self.0.right().to_scalar(&partial.1)?; + let dtype = self + .0 + .partial_struct_dtype(l_scalar.dtype().clone(), r_scalar.dtype().clone()); + Ok(Scalar::struct_(dtype, vec![l_scalar, r_scalar])) + } + + fn reset(&self, partial: &mut Self::Partial) { + self.0.left().reset(&mut partial.0); + self.0.right().reset(&mut partial.1); + } + + fn is_saturated(&self, partial: &Self::Partial) -> bool { + self.0.left().is_saturated(&partial.0) && self.0.right().is_saturated(&partial.1) + } + + /// Fans out to each child's `try_accumulate`, falling back to `accumulate` + /// against a lazily-canonicalized batch. We always claim to handle the + /// batch ourselves so [`Self::accumulate`] is unreachable — this is the + /// same trick `Count` uses to opt out of the canonicalization path. + fn try_accumulate( + &self, + state: &mut Self::Partial, + batch: &ArrayRef, + ctx: &mut ExecutionCtx, + ) -> VortexResult { + let mut canonical: Option = None; + if !self.0.left().try_accumulate(&mut state.0, batch, ctx)? { + let c = canonical.insert(batch.clone().execute::(ctx)?); + self.0.left().accumulate(&mut state.0, c, ctx)?; + } + if !self.0.right().try_accumulate(&mut state.1, batch, ctx)? { + let c = match canonical.as_ref() { + Some(c) => c, + None => canonical.insert(batch.clone().execute::(ctx)?), + }; + self.0.right().accumulate(&mut state.1, c, ctx)?; + } + Ok(true) + } + + fn accumulate( + &self, + _state: &mut Self::Partial, + _batch: &Columnar, + _ctx: &mut ExecutionCtx, + ) -> VortexResult<()> { + unreachable!("Combined::try_accumulate handles all batches") + } + + fn finalize(&self, states: ArrayRef) -> VortexResult { + let l_field = states.get_item(FieldName::from(self.0.left_name()))?; + let r_field = states.get_item(FieldName::from(self.0.right_name()))?; + let l_finalized = self.0.left().finalize(l_field)?; + let r_finalized = self.0.right().finalize(r_field)?; + BinaryCombined::finalize(&self.0, l_finalized, r_finalized) + } + + fn finalize_scalar(&self, partial: &Self::Partial) -> VortexResult { + let l_scalar = self.0.left().finalize_scalar(&partial.0)?; + let r_scalar = self.0.right().finalize_scalar(&partial.1)?; + BinaryCombined::finalize_scalar(&self.0, l_scalar, r_scalar) + } +} diff --git a/vortex-array/src/aggregate_fn/fns/mean/mod.rs b/vortex-array/src/aggregate_fn/fns/mean/mod.rs new file mode 100644 index 00000000000..f7d471023ee --- /dev/null +++ b/vortex-array/src/aggregate_fn/fns/mean/mod.rs @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use vortex_error::VortexResult; +use vortex_error::vortex_bail; + +use crate::ArrayRef; +use crate::ExecutionCtx; +use crate::aggregate_fn::Accumulator; +use crate::aggregate_fn::AggregateFnId; +use crate::aggregate_fn::AggregateFnVTable; +use crate::aggregate_fn::DynAccumulator; +use crate::aggregate_fn::EmptyOptions; +use crate::aggregate_fn::combined::BinaryCombined; +use crate::aggregate_fn::combined::Combined; +use crate::aggregate_fn::combined::CombinedOptions; +use crate::aggregate_fn::combined::PairOptions; +use crate::aggregate_fn::fns::count::Count; +use crate::aggregate_fn::fns::sum::Sum; +use crate::builtins::ArrayBuiltins; +use crate::dtype::DType; +use crate::dtype::Nullability; +use crate::dtype::PType; +use crate::scalar::Scalar; +use crate::scalar_fn::fns::operators::Operator; + +/// Compute the arithmetic mean of an array. +/// +/// See [`Mean`] for details. +pub fn mean(array: &ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult { + let mut acc = Accumulator::try_new( + Mean::combined(), + PairOptions(EmptyOptions, EmptyOptions), + array.dtype().clone(), + )?; + acc.accumulate(array, ctx)?; + acc.finish() +} + +/// Compute the arithmetic mean of an array. +/// +/// Implemented as `Sum / Count` via [`BinaryCombined`]. +/// +/// Coercion / return type: +/// - Booleans and primitive numeric types are coerced to `f64` and the result +/// is a nullable `f64`. +/// - Decimals are kept as decimals but not implemented currently +#[derive(Clone, Debug)] +pub struct Mean; + +impl Mean { + pub fn combined() -> Combined { + Combined(Mean) + } +} + +impl BinaryCombined for Mean { + type Left = Sum; + type Right = Count; + + fn id(&self) -> AggregateFnId { + AggregateFnId::new("vortex.mean") + } + + fn left(&self) -> Sum { + Sum + } + + fn right(&self) -> Count { + Count + } + + fn left_name(&self) -> &'static str { + "sum" + } + + fn right_name(&self) -> &'static str { + "count" + } + + fn return_dtype(&self, input_dtype: &DType) -> Option { + Some(mean_output_dtype(input_dtype)?.with_nullability(Nullability::Nullable)) + } + + fn finalize(&self, sum: ArrayRef, count: ArrayRef) -> VortexResult { + let target = match sum.dtype() { + DType::Decimal(..) => sum.dtype().with_nullability(Nullability::Nullable), + _ => DType::Primitive(PType::F64, Nullability::Nullable), + }; + let sum_cast = sum.cast(target.clone())?; + let count_cast = count.cast(target)?; + sum_cast.binary(count_cast, Operator::Div) + } + + fn finalize_scalar(&self, left_scalar: Scalar, right_scalar: Scalar) -> VortexResult { + if let DType::Decimal(..) = left_scalar.dtype() { + vortex_bail!("mean::finalize_scalar not yet implemented for decimal inputs"); + } + + let target = DType::Primitive(PType::F64, Nullability::Nullable); + let sum_cast = left_scalar.cast(&target)?; + let count_cast = right_scalar.cast(&target)?; + + let sum = sum_cast.as_primitive().typed_value::(); + let count = count_cast.as_primitive().typed_value::(); + let value = match (sum, count) { + (None, _) | (_, None) | (_, Some(0.0)) => return Ok(Scalar::null(target)), // Sum overflowed + (Some(s), Some(c)) => s / c, + }; + Ok(Scalar::primitive(value, Nullability::Nullable)) + } + + fn serialize(&self, _options: &CombinedOptions) -> VortexResult>> { + unimplemented!("mean is not yet serializable"); + } + + fn coerce_args( + &self, + _options: &PairOptions< + ::Options, + ::Options, + >, + input_dtype: &DType, + ) -> VortexResult { + // Advisory hint for query planners: where possible, cast input to the + // type we're going to compute the mean in. + Ok(coerced_input_dtype(input_dtype).unwrap_or_else(|| input_dtype.clone())) + } +} + +/// Hint for callers: what to cast the input to before accumulation. +/// +/// - Bool stays as bool — `Sum` has a native bool path and bool → f64 isn't +/// currently a direct cast in vortex. +/// - Primitive numerics → `f64` so the sum and finalize work without overflow. +fn coerced_input_dtype(input_dtype: &DType) -> Option { + match input_dtype { + DType::Bool(_) => Some(input_dtype.clone()), + DType::Primitive(_, n) => Some(DType::Primitive(PType::F64, *n)), + DType::Decimal(..) => { + unimplemented!("mean is not implemented for decimals yet") + } + _ => None, + } +} + +fn mean_output_dtype(input_dtype: &DType) -> Option { + match input_dtype { + DType::Bool(_) | DType::Primitive(..) => { + Some(DType::Primitive(PType::F64, Nullability::Nullable)) + } + DType::Decimal(..) => { + unimplemented!("mean for decimals is not yet implemented"); + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use vortex_buffer::buffer; + use vortex_error::VortexResult; + + use super::*; + use crate::IntoArray; + use crate::LEGACY_SESSION; + use crate::VortexSessionExecute; + use crate::arrays::BoolArray; + use crate::arrays::ChunkedArray; + use crate::arrays::ConstantArray; + use crate::arrays::PrimitiveArray; + use crate::validity::Validity; + + #[test] + fn mean_all_valid() -> VortexResult<()> { + let array = PrimitiveArray::new(buffer![1.0f64, 2.0, 3.0, 4.0, 5.0], Validity::NonNullable) + .into_array(); + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let result = mean(&array, &mut ctx)?; + assert_eq!(result.as_primitive().as_::(), Some(3.0)); + Ok(()) + } + + #[test] + fn mean_with_nulls() -> VortexResult<()> { + let array = PrimitiveArray::from_option_iter([Some(2.0f64), None, Some(4.0)]).into_array(); + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let result = mean(&array, &mut ctx)?; + assert_eq!(result.as_primitive().as_::(), Some(3.0)); + Ok(()) + } + + #[test] + fn mean_integers() -> VortexResult<()> { + let array = PrimitiveArray::new(buffer![10i32, 20, 30], Validity::NonNullable).into_array(); + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let result = mean(&array, &mut ctx)?; + assert_eq!(result.as_primitive().as_::(), Some(20.0)); + Ok(()) + } + + #[test] + fn mean_bool() -> VortexResult<()> { + let array: BoolArray = [true, false, true, true].into_iter().collect(); + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let result = mean(&array.into_array(), &mut ctx)?; + assert_eq!(result.as_primitive().as_::(), Some(0.75)); + Ok(()) + } + + #[test] + fn mean_constant_non_null() -> VortexResult<()> { + let array = ConstantArray::new(5.0f64, 4); + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let result = mean(&array.into_array(), &mut ctx)?; + assert_eq!(result.as_primitive().as_::(), Some(5.0)); + Ok(()) + } + + #[test] + fn mean_chunked() -> VortexResult<()> { + let chunk1 = PrimitiveArray::from_option_iter([Some(1.0f64), None, Some(3.0)]); + let chunk2 = PrimitiveArray::from_option_iter([Some(5.0f64), None]); + let dtype = chunk1.dtype().clone(); + let chunked = ChunkedArray::try_new(vec![chunk1.into_array(), chunk2.into_array()], dtype)?; + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let result = mean(&chunked.into_array(), &mut ctx)?; + assert_eq!(result.as_primitive().as_::(), Some(3.0)); + Ok(()) + } + + #[test] + fn mean_all_null_returns_null() -> VortexResult<()> { + let array = PrimitiveArray::from_option_iter::([None, None, None]).into_array(); + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let result = mean(&array, &mut ctx)?; + assert_eq!(result.as_primitive().as_::(), None); + Ok(()) + } + + #[test] + fn mean_multi_batch() -> VortexResult<()> { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let dtype = DType::Primitive(PType::F64, Nullability::NonNullable); + let mut acc = Accumulator::try_new( + Mean::combined(), + PairOptions(EmptyOptions, EmptyOptions), + dtype, + )?; + + let batch1 = + PrimitiveArray::new(buffer![1.0f64, 2.0, 3.0], Validity::NonNullable).into_array(); + acc.accumulate(&batch1, &mut ctx)?; + + let batch2 = PrimitiveArray::new(buffer![4.0f64, 5.0], Validity::NonNullable).into_array(); + acc.accumulate(&batch2, &mut ctx)?; + + let result = acc.finish()?; + assert_eq!(result.as_primitive().as_::(), Some(3.0)); + Ok(()) + } +} diff --git a/vortex-array/src/aggregate_fn/fns/mod.rs b/vortex-array/src/aggregate_fn/fns/mod.rs index 38d5340cd1f..f1281c18544 100644 --- a/vortex-array/src/aggregate_fn/fns/mod.rs +++ b/vortex-array/src/aggregate_fn/fns/mod.rs @@ -6,6 +6,7 @@ pub mod first; pub mod is_constant; pub mod is_sorted; pub mod last; +pub mod mean; pub mod min_max; pub mod nan_count; pub mod sum; diff --git a/vortex-array/src/aggregate_fn/mod.rs b/vortex-array/src/aggregate_fn/mod.rs index b697265e62b..1bcd2cac030 100644 --- a/vortex-array/src/aggregate_fn/mod.rs +++ b/vortex-array/src/aggregate_fn/mod.rs @@ -32,6 +32,7 @@ pub use erased::*; mod options; pub use options::*; +pub mod combined; pub mod fns; pub mod kernels; pub mod proto; diff --git a/vortex-array/src/aggregate_fn/session.rs b/vortex-array/src/aggregate_fn/session.rs index 886b1ea9c2d..17720398f6c 100644 --- a/vortex-array/src/aggregate_fn/session.rs +++ b/vortex-array/src/aggregate_fn/session.rs @@ -1,11 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::any::Any; use std::sync::Arc; use parking_lot::RwLock; use vortex_session::Ref; use vortex_session::SessionExt; +use vortex_session::SessionVar; use vortex_session::registry::Registry; use vortex_utils::aliases::hash_map::HashMap; @@ -42,6 +44,16 @@ pub struct AggregateFnSession { pub(super) grouped_kernels: RwLock>, } +impl SessionVar for AggregateFnSession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + type KernelKey = (ArrayId, Option); impl Default for AggregateFnSession { diff --git a/vortex-array/src/arrays/masked/array.rs b/vortex-array/src/arrays/masked/array.rs index 54924f8053f..5253156d1fb 100644 --- a/vortex-array/src/arrays/masked/array.rs +++ b/vortex-array/src/arrays/masked/array.rs @@ -4,7 +4,6 @@ use std::fmt::Display; use std::fmt::Formatter; -use vortex_error::VortexExpect; use vortex_error::VortexResult; use vortex_error::vortex_bail; @@ -16,15 +15,17 @@ use crate::array::ArrayParts; use crate::array::TypedArrayRef; use crate::array::child_to_validity; use crate::array::validity_to_child; +use crate::array_slots; use crate::arrays::Masked; use crate::validity::Validity; -/// The underlying child array being masked. -pub(super) const CHILD_SLOT: usize = 0; -/// The validity bitmap defining which elements are non-null. -pub(super) const VALIDITY_SLOT: usize = 1; -pub(super) const NUM_SLOTS: usize = 2; -pub(super) const SLOT_NAMES: [&str; NUM_SLOTS] = ["child", "validity"]; +#[array_slots(Masked)] +pub struct MaskedSlots { + /// The underlying child array being masked. + pub child: ArrayRef, + /// The validity bitmap defining which elements are non-null. + pub validity: Option, +} #[derive(Clone, Debug)] pub struct MaskedData; @@ -35,22 +36,10 @@ impl Display for MaskedData { } } -pub trait MaskedArrayExt: TypedArrayRef { - fn child(&self) -> &ArrayRef { - self.as_ref().slots()[CHILD_SLOT] - .as_ref() - .vortex_expect("validated masked child slot") - } - - fn validity_child(&self) -> Option<&ArrayRef> { - self.as_ref().slots()[VALIDITY_SLOT].as_ref() - } - +pub trait MaskedArrayExt: TypedArrayRef + MaskedArraySlotsExt { fn masked_validity(&self) -> Validity { - child_to_validity( - &self.as_ref().slots()[VALIDITY_SLOT], - self.as_ref().dtype().nullability(), - ) + let x = &self.as_ref().slots()[MaskedSlots::VALIDITY]; + child_to_validity(x, self.as_ref().dtype().nullability()) } } impl> MaskedArrayExt for T {} diff --git a/vortex-array/src/arrays/masked/compute/filter.rs b/vortex-array/src/arrays/masked/compute/filter.rs index fb3969b4bb8..9ea6b168105 100644 --- a/vortex-array/src/arrays/masked/compute/filter.rs +++ b/vortex-array/src/arrays/masked/compute/filter.rs @@ -10,7 +10,7 @@ use crate::array::ArrayView; use crate::arrays::Masked; use crate::arrays::MaskedArray; use crate::arrays::filter::FilterReduce; -use crate::arrays::masked::MaskedArrayExt; +use crate::arrays::masked::MaskedArraySlotsExt; impl FilterReduce for Masked { fn filter(array: ArrayView<'_, Masked>, mask: &Mask) -> VortexResult> { diff --git a/vortex-array/src/arrays/masked/compute/mask.rs b/vortex-array/src/arrays/masked/compute/mask.rs index d8590a68d34..514d0aeaafc 100644 --- a/vortex-array/src/arrays/masked/compute/mask.rs +++ b/vortex-array/src/arrays/masked/compute/mask.rs @@ -6,7 +6,7 @@ use vortex_error::VortexResult; use crate::ArrayRef; use crate::array::ArrayView; use crate::arrays::Masked; -use crate::arrays::masked::MaskedArrayExt; +use crate::arrays::masked::MaskedArraySlotsExt; use crate::arrays::scalar_fn::ScalarFnFactoryExt; use crate::scalar_fn::EmptyOptions; use crate::scalar_fn::fns::mask::Mask as MaskExpr; diff --git a/vortex-array/src/arrays/masked/compute/slice.rs b/vortex-array/src/arrays/masked/compute/slice.rs index fe295bd6826..5a51ca9f681 100644 --- a/vortex-array/src/arrays/masked/compute/slice.rs +++ b/vortex-array/src/arrays/masked/compute/slice.rs @@ -10,7 +10,7 @@ use crate::IntoArray; use crate::array::ArrayView; use crate::arrays::Masked; use crate::arrays::MaskedArray; -use crate::arrays::masked::MaskedArrayExt; +use crate::arrays::masked::MaskedArraySlotsExt; use crate::arrays::slice::SliceReduce; impl SliceReduce for Masked { diff --git a/vortex-array/src/arrays/masked/compute/take.rs b/vortex-array/src/arrays/masked/compute/take.rs index 958a848d180..1eff686b4d9 100644 --- a/vortex-array/src/arrays/masked/compute/take.rs +++ b/vortex-array/src/arrays/masked/compute/take.rs @@ -9,7 +9,7 @@ use crate::array::ArrayView; use crate::arrays::Masked; use crate::arrays::MaskedArray; use crate::arrays::dict::TakeReduce; -use crate::arrays::masked::MaskedArrayExt; +use crate::arrays::masked::MaskedArraySlotsExt; use crate::builtins::ArrayBuiltins; use crate::scalar::Scalar; use crate::validity::Validity; diff --git a/vortex-array/src/arrays/masked/execute.rs b/vortex-array/src/arrays/masked/execute.rs index 4bc6449ead3..354b246405c 100644 --- a/vortex-array/src/arrays/masked/execute.rs +++ b/vortex-array/src/arrays/masked/execute.rs @@ -3,11 +3,9 @@ //! Execution logic for MaskedArray - applies a validity mask to canonical arrays. -use std::ops::BitAnd; use std::sync::Arc; use vortex_error::VortexResult; -use vortex_mask::Mask; use crate::Canonical; use crate::IntoArray; @@ -17,7 +15,6 @@ use crate::arrays::ExtensionArray; use crate::arrays::FixedSizeListArray; use crate::arrays::ListViewArray; use crate::arrays::MaskedArray; -use crate::arrays::NullArray; use crate::arrays::PrimitiveArray; use crate::arrays::StructArray; use crate::arrays::VarBinViewArray; @@ -28,9 +25,7 @@ use crate::arrays::fixed_size_list::FixedSizeListArrayExt; use crate::arrays::listview::ListViewArrayExt; use crate::arrays::struct_::StructArrayExt; use crate::arrays::variant::VariantArrayExt; -use crate::dtype::Nullability; use crate::executor::ExecutionCtx; -use crate::match_each_decimal_value_type; use crate::validity::Validity; /// TODO: replace usage of compute fn. @@ -40,64 +35,36 @@ use crate::validity::Validity; /// validity with the provided mask, marking additional positions as invalid. pub fn mask_validity_canonical( canonical: Canonical, - validity_mask: &Mask, + validity: Validity, ctx: &mut ExecutionCtx, ) -> VortexResult { Ok(match canonical { - Canonical::Null(a) => Canonical::Null(mask_validity_null(a, validity_mask)), - Canonical::Bool(a) => Canonical::Bool(mask_validity_bool(a, validity_mask, ctx)?), - Canonical::Primitive(a) => { - Canonical::Primitive(mask_validity_primitive(a, validity_mask, ctx)?) - } - Canonical::Decimal(a) => Canonical::Decimal(mask_validity_decimal(a, validity_mask, ctx)?), - Canonical::VarBinView(a) => { - Canonical::VarBinView(mask_validity_varbinview(a, validity_mask, ctx)?) - } - Canonical::List(a) => Canonical::List(mask_validity_listview(a, validity_mask, ctx)?), + n @ Canonical::Null(_) => n, + Canonical::Bool(a) => Canonical::Bool(mask_validity_bool(a, validity)?), + Canonical::Primitive(a) => Canonical::Primitive(mask_validity_primitive(a, validity)?), + Canonical::Decimal(a) => Canonical::Decimal(mask_validity_decimal(a, validity)?), + Canonical::VarBinView(a) => Canonical::VarBinView(mask_validity_varbinview(a, validity)?), + Canonical::List(a) => Canonical::List(mask_validity_listview(a, validity)?), Canonical::FixedSizeList(a) => { - Canonical::FixedSizeList(mask_validity_fixed_size_list(a, validity_mask, ctx)?) + Canonical::FixedSizeList(mask_validity_fixed_size_list(a, validity)?) } - Canonical::Struct(a) => Canonical::Struct(mask_validity_struct(a, validity_mask, ctx)?), - Canonical::Extension(a) => { - Canonical::Extension(mask_validity_extension(a, validity_mask, ctx)?) - } - Canonical::Variant(a) => Canonical::Variant(mask_validity_variant(a, validity_mask, ctx)?), + Canonical::Struct(a) => Canonical::Struct(mask_validity_struct(a, validity)?), + Canonical::Extension(a) => Canonical::Extension(mask_validity_extension(a, validity, ctx)?), + Canonical::Variant(a) => Canonical::Variant(mask_validity_variant(a, validity)?), }) } -fn combine_validity( - validity: &Validity, - mask: &Mask, - len: usize, - ctx: &mut ExecutionCtx, -) -> VortexResult { - let current_mask = validity.execute_mask(len, ctx)?; - let combined = current_mask.bitand(mask); - Ok(Validity::from_mask(combined, Nullability::Nullable)) -} - -fn mask_validity_null(array: NullArray, _mask: &Mask) -> NullArray { - array -} - -fn mask_validity_bool( - array: BoolArray, - mask: &Mask, - ctx: &mut ExecutionCtx, -) -> VortexResult { - let len = array.len(); - let new_validity = combine_validity(&array.validity()?, mask, len, ctx)?; +fn mask_validity_bool(array: BoolArray, mask: Validity) -> VortexResult { + let new_validity = Validity::and(array.validity()?, mask)?; Ok(BoolArray::new(array.to_bit_buffer(), new_validity)) } fn mask_validity_primitive( array: PrimitiveArray, - mask: &Mask, - ctx: &mut ExecutionCtx, + validity: Validity, ) -> VortexResult { - let len = array.len(); let ptype = array.ptype(); - let new_validity = combine_validity(&array.validity()?, mask, len, ctx)?; + let new_validity = Validity::and(array.validity()?, validity)?; // SAFETY: validity has same length as values Ok(unsafe { PrimitiveArray::new_unchecked_from_handle( @@ -108,31 +75,26 @@ fn mask_validity_primitive( }) } -fn mask_validity_decimal( - array: DecimalArray, - mask: &Mask, - ctx: &mut ExecutionCtx, -) -> VortexResult { - let len = array.len(); - let dec_dtype = array.decimal_dtype(); - let values_type = array.values_type(); - let new_validity = combine_validity(&array.validity()?, mask, len, ctx)?; +fn mask_validity_decimal(array: DecimalArray, validity: Validity) -> VortexResult { + let new_validity = Validity::and(array.validity()?, validity)?; // SAFETY: We're only changing validity, not the data structure - Ok(match_each_decimal_value_type!(values_type, |T| { - let buffer = array.buffer::(); - unsafe { DecimalArray::new_unchecked(buffer, dec_dtype, new_validity) } - })) + Ok(unsafe { + DecimalArray::new_unchecked_handle( + array.buffer_handle().clone(), + array.values_type(), + array.decimal_dtype(), + new_validity, + ) + }) } /// Mask validity for VarBinViewArray. fn mask_validity_varbinview( array: VarBinViewArray, - mask: &Mask, - ctx: &mut ExecutionCtx, + validity: Validity, ) -> VortexResult { - let len = array.len(); let dtype = array.dtype().as_nullable(); - let new_validity = combine_validity(&array.validity()?, mask, len, ctx)?; + let new_validity = Validity::and(array.validity()?, validity)?; // SAFETY: We're only changing validity, not the data structure Ok(unsafe { VarBinViewArray::new_handle_unchecked( @@ -144,13 +106,8 @@ fn mask_validity_varbinview( }) } -fn mask_validity_listview( - array: ListViewArray, - mask: &Mask, - ctx: &mut ExecutionCtx, -) -> VortexResult { - let len = array.len(); - let new_validity = combine_validity(&array.validity()?, mask, len, ctx)?; +fn mask_validity_listview(array: ListViewArray, validity: Validity) -> VortexResult { + let new_validity = Validity::and(array.validity()?, validity)?; // SAFETY: We're only changing validity, not the data structure Ok(unsafe { ListViewArray::new_unchecked( @@ -164,25 +121,20 @@ fn mask_validity_listview( fn mask_validity_fixed_size_list( array: FixedSizeListArray, - mask: &Mask, - ctx: &mut ExecutionCtx, + validity: Validity, ) -> VortexResult { let len = array.len(); let list_size = array.list_size(); - let new_validity = combine_validity(&array.validity()?, mask, len, ctx)?; + let new_validity = Validity::and(array.validity()?, validity)?; // SAFETY: We're only changing validity, not the data structure Ok(unsafe { FixedSizeListArray::new_unchecked(array.elements().clone(), list_size, new_validity, len) }) } -fn mask_validity_struct( - array: StructArray, - mask: &Mask, - ctx: &mut ExecutionCtx, -) -> VortexResult { +fn mask_validity_struct(array: StructArray, validity: Validity) -> VortexResult { let len = array.len(); - let new_validity = combine_validity(&array.validity()?, mask, len, ctx)?; + let new_validity = Validity::and(array.validity()?, validity)?; let fields = array.unmasked_fields(); let struct_fields = array.struct_fields(); // SAFETY: We're only changing validity, not the data structure @@ -191,12 +143,12 @@ fn mask_validity_struct( fn mask_validity_extension( array: ExtensionArray, - mask: &Mask, + validity: Validity, ctx: &mut ExecutionCtx, ) -> VortexResult { // For extension arrays, we need to mask the underlying storage let storage = array.storage_array().clone().execute::(ctx)?; - let masked_storage = mask_validity_canonical(storage, mask, ctx)?; + let masked_storage = mask_validity_canonical(storage, validity, ctx)?; let masked_storage = masked_storage.into_array(); Ok(ExtensionArray::new( array @@ -206,11 +158,7 @@ fn mask_validity_extension( )) } -fn mask_validity_variant( - array: VariantArray, - mask: &Mask, - ctx: &mut ExecutionCtx, -) -> VortexResult { +fn mask_validity_variant(array: VariantArray, validity: Validity) -> VortexResult { let child = array.child().clone(); let len = child.len(); let child_validity = child.validity()?; @@ -218,8 +166,7 @@ fn mask_validity_variant( match child_validity { Validity::NonNullable | Validity::AllValid => { // Child has no nulls — wrap in MaskedArray to apply the mask. - let new_validity = Validity::from_mask(mask.clone(), Nullability::Nullable); - let masked_child = MaskedArray::try_new(child, new_validity)?; + let masked_child = MaskedArray::try_new(child, validity)?; Ok(VariantArray::new(masked_child.into_array())) } Validity::AllInvalid => { @@ -229,7 +176,7 @@ fn mask_validity_variant( Validity::Array(_) => { // Child has an array-backed validity stored as its first child. // Combine with the mask and replace that child via with_children. - let combined = combine_validity(&child_validity, mask, len, ctx)?; + let combined = Validity::and(child_validity, validity)?; let new_child = child.with_slot(0, combined.to_array(len))?; Ok(VariantArray::new(new_child)) } diff --git a/vortex-array/src/arrays/masked/mod.rs b/vortex-array/src/arrays/masked/mod.rs index ac437d30321..7e23653c1c4 100644 --- a/vortex-array/src/arrays/masked/mod.rs +++ b/vortex-array/src/arrays/masked/mod.rs @@ -3,7 +3,9 @@ mod array; pub use array::MaskedArrayExt; +pub use array::MaskedArraySlotsExt; pub use array::MaskedData; +pub use array::MaskedSlots; pub use vtable::MaskedArray; pub(crate) mod compute; diff --git a/vortex-array/src/arrays/masked/vtable/mod.rs b/vortex-array/src/arrays/masked/vtable/mod.rs index d4eb457c434..2ef10ba0082 100644 --- a/vortex-array/src/arrays/masked/vtable/mod.rs +++ b/vortex-array/src/arrays/masked/vtable/mod.rs @@ -30,10 +30,9 @@ use crate::array::VTable; use crate::array::validity_to_child; use crate::arrays::ConstantArray; use crate::arrays::masked::MaskedArrayExt; +use crate::arrays::masked::MaskedArraySlotsExt; use crate::arrays::masked::MaskedData; -use crate::arrays::masked::array::CHILD_SLOT; -use crate::arrays::masked::array::SLOT_NAMES; -use crate::arrays::masked::array::VALIDITY_SLOT; +use crate::arrays::masked::array::MaskedSlots; use crate::arrays::masked::compute::rules::PARENT_RULES; use crate::arrays::masked::mask_validity_canonical; use crate::buffer::BufferHandle; @@ -41,7 +40,6 @@ use crate::dtype::DType; use crate::executor::ExecutionCtx; use crate::executor::ExecutionResult; use crate::require_child; -use crate::require_validity; use crate::scalar::Scalar; use crate::serde::ArrayChildren; use crate::validity::Validity; @@ -80,10 +78,10 @@ impl VTable for Masked { slots: &[Option], ) -> VortexResult<()> { vortex_ensure!( - slots[CHILD_SLOT].is_some(), + slots[MaskedSlots::CHILD].is_some(), "MaskedArray child slot must be present" ); - let child = slots[CHILD_SLOT] + let child = slots[MaskedSlots::CHILD] .as_ref() .vortex_expect("validated child slot"); vortex_ensure!(child.len() == len, "MaskedArray child length mismatch"); @@ -161,10 +159,12 @@ impl VTable for Masked { } fn execute(array: Array, ctx: &mut ExecutionCtx) -> VortexResult { - let validity_mask = array.masked_validity().execute_mask(array.len(), ctx)?; + let array = require_child!(array, array.child(), MaskedSlots::CHILD => AnyCanonical); + + let validity = array.masked_validity(); // Fast path: all masked means result is all nulls. - if validity_mask.all_false() { + if matches!(validity, Validity::AllInvalid) { return Ok(ExecutionResult::done( ConstantArray::new(Scalar::null(array.dtype().as_nullable()), array.len()) .into_array(), @@ -177,12 +177,9 @@ impl VTable for Masked { // While we could manually convert the dtype, `mask_validity_canonical` is already O(1) for // `AllTrue` masks (no data copying), so there's no benefit. - let array = require_child!(array, array.child(), CHILD_SLOT => AnyCanonical); - require_validity!(array, VALIDITY_SLOT); - let child = Canonical::from(array.child().as_::()); Ok(ExecutionResult::done( - mask_validity_canonical(child, &validity_mask, ctx)?.into_array(), + mask_validity_canonical(child, validity, ctx)?.into_array(), )) } @@ -194,7 +191,7 @@ impl VTable for Masked { PARENT_RULES.evaluate(array, parent, child_idx) } fn slot_name(_array: ArrayView<'_, Self>, idx: usize) -> String { - SLOT_NAMES[idx].to_string() + MaskedSlots::NAMES[idx].to_string() } } diff --git a/vortex-array/src/arrays/masked/vtable/operations.rs b/vortex-array/src/arrays/masked/vtable/operations.rs index 294cd840376..c82d0bf03ed 100644 --- a/vortex-array/src/arrays/masked/vtable/operations.rs +++ b/vortex-array/src/arrays/masked/vtable/operations.rs @@ -7,7 +7,7 @@ use crate::ExecutionCtx; use crate::array::ArrayView; use crate::array::OperationsVTable; use crate::arrays::Masked; -use crate::arrays::masked::MaskedArrayExt; +use crate::arrays::masked::MaskedArraySlotsExt; use crate::scalar::Scalar; impl OperationsVTable for Masked { diff --git a/vortex-array/src/arrow/executor/temporal.rs b/vortex-array/src/arrow/executor/temporal.rs index 6fa8e93e704..c68a4f3ee9f 100644 --- a/vortex-array/src/arrow/executor/temporal.rs +++ b/vortex-array/src/arrow/executor/temporal.rs @@ -86,16 +86,16 @@ pub(super) fn to_arrow_temporal( match (unit, arrow_unit) { (TimeUnit::Seconds, ArrowTimeUnit::Second) => { - to_arrow_timestamp::(array, arrow_tz, ctx) + to_arrow_timestamp::(array, arrow_tz.as_ref(), ctx) } (TimeUnit::Milliseconds, ArrowTimeUnit::Millisecond) => { - to_arrow_timestamp::(array, arrow_tz, ctx) + to_arrow_timestamp::(array, arrow_tz.as_ref(), ctx) } (TimeUnit::Microseconds, ArrowTimeUnit::Microsecond) => { - to_arrow_timestamp::(array, arrow_tz, ctx) + to_arrow_timestamp::(array, arrow_tz.as_ref(), ctx) } (TimeUnit::Nanoseconds, ArrowTimeUnit::Nanosecond) => { - to_arrow_timestamp::(array, arrow_tz, ctx) + to_arrow_timestamp::(array, arrow_tz.as_ref(), ctx) } _ => vortex_bail!( "Cannot convert {} array to Arrow type {}", @@ -125,14 +125,14 @@ where fn to_arrow_timestamp( array: ArrayRef, - arrow_tz: &Option>, + arrow_tz: Option<&Arc>, ctx: &mut ExecutionCtx, ) -> VortexResult where T::Native: NativePType, { Ok(Arc::new( - to_arrow_temporal_primitive::(array, ctx)?.with_timezone_opt(arrow_tz.clone()), + to_arrow_temporal_primitive::(array, ctx)?.with_timezone_opt(arrow_tz.cloned()), )) } diff --git a/vortex-array/src/dtype/session.rs b/vortex-array/src/dtype/session.rs index 669aab68165..2314658869f 100644 --- a/vortex-array/src/dtype/session.rs +++ b/vortex-array/src/dtype/session.rs @@ -3,10 +3,12 @@ //! Module for managing extension dtypes in a Vortex session. +use std::any::Any; use std::sync::Arc; use vortex_session::Ref; use vortex_session::SessionExt; +use vortex_session::SessionVar; use vortex_session::registry::Registry; use crate::dtype::extension::ExtDTypePluginRef; @@ -39,6 +41,16 @@ impl Default for DTypeSession { } } +impl SessionVar for DTypeSession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + impl DTypeSession { /// Register an extension DType with the Vortex session. pub fn register(&self, vtable: V) { diff --git a/vortex-array/src/expr/pruning/pruning_expr.rs b/vortex-array/src/expr/pruning/pruning_expr.rs index bf985cad861..00d29fbcf99 100644 --- a/vortex-array/src/expr/pruning/pruning_expr.rs +++ b/vortex-array/src/expr/pruning/pruning_expr.rs @@ -86,6 +86,11 @@ pub fn field_path_stat_field_name(field_path: &FieldPath, stat: Stat) -> FieldNa /// cannot hold, and false if it cannot be determined from stats alone whether the positions can /// be pruned. /// +/// Some rewrites, such as `is_not_null(...)`, emit +/// [`row_count`][crate::scalar_fn::internal::row_count] placeholders. The evaluation layer must +/// replace those placeholders with the row count for its current scope before +/// executing the returned expression. +/// /// If the falsification logic attempts to access an unknown stat, /// this function will return `None`. pub fn checked_pruning_expr( diff --git a/vortex-array/src/memory.rs b/vortex-array/src/memory.rs index 47030b18131..d3669e49f93 100644 --- a/vortex-array/src/memory.rs +++ b/vortex-array/src/memory.rs @@ -3,6 +3,7 @@ //! Session-scoped memory allocation for host-side buffers. +use std::any::Any; use std::fmt::Debug; use std::mem::size_of; use std::sync::Arc; @@ -18,6 +19,7 @@ use vortex_error::vortex_err; use vortex_session::Ref; use vortex_session::RefMut; use vortex_session::SessionExt; +use vortex_session::SessionVar; /// Mutable host buffer contract used by [`WritableHostBuffer`]. pub trait HostBufferMut: Send + 'static { @@ -199,6 +201,16 @@ impl Default for MemorySession { } } +impl SessionVar for MemorySession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Extension trait for accessing session-scoped memory configuration. pub trait MemorySessionExt: SessionExt { /// Returns the memory session for this execution/session context. diff --git a/vortex-array/src/optimizer/kernels.rs b/vortex-array/src/optimizer/kernels.rs index af70d0f9b9b..a31192f8016 100644 --- a/vortex-array/src/optimizer/kernels.rs +++ b/vortex-array/src/optimizer/kernels.rs @@ -17,6 +17,7 @@ //! sessions can add it with [`VortexSession::with`](vortex_session::VortexSession::with) or rely //! on [`ArrayKernelsExt::kernels`] to insert the default value. +use std::any::Any; use std::hash::BuildHasher; use std::sync::Arc; use std::sync::LazyLock; @@ -25,6 +26,7 @@ use arc_swap::ArcSwap; use vortex_error::VortexResult; use vortex_session::Ref; use vortex_session::SessionExt; +use vortex_session::SessionVar; use vortex_session::registry::Id; use vortex_utils::aliases::DefaultHashBuilder; use vortex_utils::aliases::hash_map::HashMap; @@ -100,6 +102,16 @@ impl ArrayKernels { } } +impl SessionVar for ArrayKernels { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Extension trait for accessing optimizer kernels from a /// [`VortexSession`](vortex_session::VortexSession). pub trait ArrayKernelsExt: SessionExt { diff --git a/vortex-array/src/scalar/arbitrary.rs b/vortex-array/src/scalar/arbitrary.rs index 6abf02ffbc3..4b74e726749 100644 --- a/vortex-array/src/scalar/arbitrary.rs +++ b/vortex-array/src/scalar/arbitrary.rs @@ -66,7 +66,7 @@ pub fn random_scalar(u: &mut Unstructured, dtype: &DType) -> Result { .vortex_expect("unable to construct random `Scalar`_"), DType::Struct(sdt, _) => Scalar::try_new( dtype.clone(), - Some(ScalarValue::List( + Some(ScalarValue::Tuple( sdt.fields() .map(|d| random_scalar(u, &d).map(|s| s.into_value())) .collect::>>()?, @@ -75,7 +75,7 @@ pub fn random_scalar(u: &mut Unstructured, dtype: &DType) -> Result { .vortex_expect("unable to construct random `Scalar`_"), DType::List(edt, _) => Scalar::try_new( dtype.clone(), - Some(ScalarValue::List( + Some(ScalarValue::Tuple( iter::from_fn(|| { // Generate elements with 1/4 probability. u.arbitrary() @@ -88,7 +88,7 @@ pub fn random_scalar(u: &mut Unstructured, dtype: &DType) -> Result { .vortex_expect("unable to construct random `Scalar`_"), DType::FixedSizeList(edt, size, _) => Scalar::try_new( dtype.clone(), - Some(ScalarValue::List( + Some(ScalarValue::Tuple( (0..*size) .map(|_| random_scalar(u, edt).map(|s| s.into_value())) .collect::>>()?, diff --git a/vortex-array/src/scalar/constructor.rs b/vortex-array/src/scalar/constructor.rs index faaddc1dcef..2baf53c9528 100644 --- a/vortex-array/src/scalar/constructor.rs +++ b/vortex-array/src/scalar/constructor.rs @@ -166,7 +166,7 @@ impl Scalar { ListKind::FixedSize => DType::FixedSizeList(element_dtype, size, nullability), }; - Self::try_new(dtype, Some(ScalarValue::List(children))) + Self::try_new(dtype, Some(ScalarValue::Tuple(children))) .vortex_expect("unable to construct a list `Scalar`") } diff --git a/vortex-array/src/scalar/convert/into_scalar.rs b/vortex-array/src/scalar/convert/into_scalar.rs index ac804c06dde..f37173d5be7 100644 --- a/vortex-array/src/scalar/convert/into_scalar.rs +++ b/vortex-array/src/scalar/convert/into_scalar.rs @@ -82,7 +82,7 @@ where Scalar: From, { fn from(vec: Vec) -> Self { - ScalarValue::List( + ScalarValue::Tuple( vec.into_iter() .map(|elem| Scalar::from(elem).into_value()) .collect(), diff --git a/vortex-array/src/scalar/downcast.rs b/vortex-array/src/scalar/downcast.rs index ce9996514e3..1276141fc35 100644 --- a/vortex-array/src/scalar/downcast.rs +++ b/vortex-array/src/scalar/downcast.rs @@ -115,12 +115,13 @@ impl Scalar { /// Returns a view of the scalar as a list scalar. /// - /// Note that we use [`ListScalar`] to represent **both** [`List`](crate::dtype::DType::List) and - /// [`FixedSizeList`](crate::dtype::DType::FixedSizeList). + /// Note that we use [`ListScalar`] to represent **both** [`List`](crate::dtype::DType::List) + /// and [`FixedSizeList`](crate::dtype::DType::FixedSizeList). /// /// # Panics /// - /// Panics if the scalar does not have a [`List`](crate::dtype::DType::List) or [`FixedSizeList`](crate::dtype::DType::FixedSizeList) type. + /// Panics if the scalar does not have a [`List`](crate::dtype::DType::List) or + /// [`FixedSizeList`](crate::dtype::DType::FixedSizeList) type. pub fn as_list(&self) -> ListScalar<'_> { self.as_list_opt() .vortex_expect("Failed to convert scalar to list") @@ -128,8 +129,8 @@ impl Scalar { /// Returns a view of the scalar as a list scalar if it has a list type. /// - /// Note that we use [`ListScalar`] to represent **both** [`List`](crate::dtype::DType::List) and - /// [`FixedSizeList`](crate::dtype::DType::FixedSizeList). + /// Note that we use [`ListScalar`] to represent **both** [`List`](crate::dtype::DType::List) + /// and [`FixedSizeList`](crate::dtype::DType::FixedSizeList). pub fn as_list_opt(&self) -> Option> { ListScalar::try_new(self.dtype(), self.value()).ok() } @@ -172,7 +173,7 @@ impl Scalar { } impl ScalarValue { - /// Returns the boolean value, panicking if the value is not a [`Bool`][ScalarValue::Bool]. + /// Returns the boolean value, panicking if the value is not a [`Bool`](ScalarValue::Bool). pub fn as_bool(&self) -> bool { match self { ScalarValue::Bool(b) => *b, @@ -181,7 +182,7 @@ impl ScalarValue { } /// Returns the primitive value, panicking if the value is not a - /// [`Primitive`][ScalarValue::Primitive]. + /// [`Primitive`](ScalarValue::Primitive). pub fn as_primitive(&self) -> &PValue { match self { ScalarValue::Primitive(p) => p, @@ -190,7 +191,7 @@ impl ScalarValue { } /// Returns the decimal value, panicking if the value is not a - /// [`Decimal`][ScalarValue::Decimal]. + /// [`Decimal`](ScalarValue::Decimal). pub fn as_decimal(&self) -> &DecimalValue { match self { ScalarValue::Decimal(d) => d, @@ -198,7 +199,7 @@ impl ScalarValue { } } - /// Returns the UTF-8 string value, panicking if the value is not a [`Utf8`][ScalarValue::Utf8]. + /// Returns the UTF-8 string value, panicking if the value is not a [`Utf8`](ScalarValue::Utf8). pub fn as_utf8(&self) -> &BufferString { match self { ScalarValue::Utf8(s) => s, @@ -206,7 +207,7 @@ impl ScalarValue { } } - /// Returns the binary value, panicking if the value is not a [`Binary`][ScalarValue::Binary]. + /// Returns the binary value, panicking if the value is not a [`Binary`](ScalarValue::Binary). pub fn as_binary(&self) -> &ByteBuffer { match self { ScalarValue::Binary(b) => b, @@ -214,15 +215,15 @@ impl ScalarValue { } } - /// Returns the list elements, panicking if the value is not a [`List`][ScalarValue::List]. + /// Returns the tuple elements, panicking if the value is not a [`Tuple`](ScalarValue::Tuple). pub fn as_list(&self) -> &[Option] { match self { - ScalarValue::List(elements) => elements, - _ => vortex_panic!("ScalarValue is not a List"), + ScalarValue::Tuple(elements) => elements, + _ => vortex_panic!("ScalarValue is not a Tuple"), } } - /// Returns the boolean value, panicking if the value is not a [`Bool`][ScalarValue::Bool]. + /// Returns the boolean value, panicking if the value is not a [`Bool`](ScalarValue::Bool). pub fn into_bool(self) -> bool { match self { ScalarValue::Bool(b) => b, @@ -231,7 +232,7 @@ impl ScalarValue { } /// Returns the primitive value, panicking if the value is not a - /// [`Primitive`][ScalarValue::Primitive]. + /// [`Primitive`](ScalarValue::Primitive). pub fn into_primitive(self) -> PValue { match self { ScalarValue::Primitive(p) => p, @@ -240,7 +241,7 @@ impl ScalarValue { } /// Returns the decimal value, panicking if the value is not a - /// [`Decimal`][ScalarValue::Decimal]. + /// [`Decimal`](ScalarValue::Decimal). pub fn into_decimal(self) -> DecimalValue { match self { ScalarValue::Decimal(d) => d, @@ -248,7 +249,7 @@ impl ScalarValue { } } - /// Returns the UTF-8 string value, panicking if the value is not a [`Utf8`][ScalarValue::Utf8]. + /// Returns the UTF-8 string value, panicking if the value is not a [`Utf8`](ScalarValue::Utf8). pub fn into_utf8(self) -> BufferString { match self { ScalarValue::Utf8(s) => s, @@ -256,7 +257,7 @@ impl ScalarValue { } } - /// Returns the binary value, panicking if the value is not a [`Binary`][ScalarValue::Binary]. + /// Returns the binary value, panicking if the value is not a [`Binary`](ScalarValue::Binary). pub fn into_binary(self) -> ByteBuffer { match self { ScalarValue::Binary(b) => b, @@ -264,11 +265,11 @@ impl ScalarValue { } } - /// Returns the list elements, panicking if the value is not a [`List`][ScalarValue::List]. + /// Returns the tuple elements, panicking if the value is not a [`Tuple`](ScalarValue::Tuple). pub fn into_list(self) -> Vec> { match self { - ScalarValue::List(elements) => elements, - _ => vortex_panic!("ScalarValue is not a List"), + ScalarValue::Tuple(elements) => elements, + _ => vortex_panic!("ScalarValue is not a Tuple"), } } diff --git a/vortex-array/src/scalar/proto.rs b/vortex-array/src/scalar/proto.rs index 2c45a450bfa..938eeb2f778 100644 --- a/vortex-array/src/scalar/proto.rs +++ b/vortex-array/src/scalar/proto.rs @@ -101,7 +101,7 @@ impl From<&ScalarValue> for pb::ScalarValue { ScalarValue::Binary(v) => pb::ScalarValue { kind: Some(Kind::BytesValue(v.to_vec())), }, - ScalarValue::List(v) => { + ScalarValue::Tuple(v) => { let mut values = Vec::with_capacity(v.len()); for elem in v.iter() { values.push(ScalarValue::to_proto(elem.as_ref())); @@ -435,7 +435,7 @@ fn bytes_from_proto(bytes: &[u8], dtype: &DType) -> VortexResult { } } -/// Deserialize a [`ScalarValue::List`] from a protobuf `ListValue`. +/// Deserialize a [`ScalarValue::Tuple`] from a protobuf `ListValue`. fn list_from_proto( v: &ListValue, dtype: &DType, @@ -454,7 +454,7 @@ fn list_from_proto( )?); } - Ok(ScalarValue::List(values)) + Ok(ScalarValue::Tuple(values)) } #[cfg(test)] @@ -531,7 +531,7 @@ mod tests { Arc::new(DType::Primitive(PType::I32, Nullability::Nullable)), Nullability::Nullable, ), - Some(ScalarValue::List(vec![ + Some(ScalarValue::Tuple(vec![ Some(ScalarValue::Primitive(42i32.into())), Some(ScalarValue::Primitive(43i32.into())), ])), diff --git a/vortex-array/src/scalar/scalar_value.rs b/vortex-array/src/scalar/scalar_value.rs index da32bafa947..2f104ef1688 100644 --- a/vortex-array/src/scalar/scalar_value.rs +++ b/vortex-array/src/scalar/scalar_value.rs @@ -33,8 +33,10 @@ pub enum ScalarValue { Utf8(BufferString), /// A binary (byte array) value. Binary(ByteBuffer), - /// A list of potentially null scalar values. - List(Vec>), + /// A tuple of potentially null scalar values. + /// + /// Used as the underlying representation for list, fixed-size list, and struct scalars. + Tuple(Vec>), /// A row-specific scalar wrapped by `DType::Variant`. Variant(Box), } @@ -49,17 +51,17 @@ impl ScalarValue { DType::Decimal(dt, ..) => Self::Decimal(DecimalValue::zero(dt)), DType::Utf8(_) => Self::Utf8(BufferString::empty()), DType::Binary(_) => Self::Binary(ByteBuffer::empty()), - DType::List(..) => Self::List(vec![]), + DType::List(..) => Self::Tuple(vec![]), DType::FixedSizeList(edt, size, _) => { let elements = (0..*size).map(|_| Some(Self::zero_value(edt))).collect(); - Self::List(elements) + Self::Tuple(elements) } DType::Struct(fields, _) => { let field_values = fields .fields() .map(|f| Some(Self::zero_value(&f))) .collect(); - Self::List(field_values) + Self::Tuple(field_values) } DType::Extension(ext_dtype) => { // Since we have no way to define a "zero" extension value (since we have no idea @@ -89,14 +91,14 @@ impl ScalarValue { DType::Decimal(dt, ..) => Self::Decimal(DecimalValue::zero(dt)), DType::Utf8(_) => Self::Utf8(BufferString::empty()), DType::Binary(_) => Self::Binary(ByteBuffer::empty()), - DType::List(..) => Self::List(vec![]), + DType::List(..) => Self::Tuple(vec![]), DType::FixedSizeList(edt, size, _) => { let elements = (0..*size).map(|_| Self::default_value(edt)).collect(); - Self::List(elements) + Self::Tuple(elements) } DType::Struct(fields, _) => { let field_values = fields.fields().map(|f| Self::default_value(&f)).collect(); - Self::List(field_values) + Self::Tuple(field_values) } DType::Extension(ext_dtype) => { // Since we have no way to define a "default" extension value (since we have no idea @@ -117,7 +119,7 @@ impl PartialOrd for ScalarValue { (ScalarValue::Decimal(a), ScalarValue::Decimal(b)) => a.partial_cmp(b), (ScalarValue::Utf8(a), ScalarValue::Utf8(b)) => a.partial_cmp(b), (ScalarValue::Binary(a), ScalarValue::Binary(b)) => a.partial_cmp(b), - (ScalarValue::List(a), ScalarValue::List(b)) => a.partial_cmp(b), + (ScalarValue::Tuple(a), ScalarValue::Tuple(b)) => a.partial_cmp(b), (ScalarValue::Variant(a), ScalarValue::Variant(b)) => a.partial_cmp(b), // (ScalarValue::Extension(a), ScalarValue::Extension(b)) => a.partial_cmp(b), _ => None, @@ -156,7 +158,7 @@ impl Display for ScalarValue { write!(f, "{}", to_hex(b)) } } - ScalarValue::List(elements) => { + ScalarValue::Tuple(elements) => { write!(f, "[")?; for (i, element) in elements.iter().enumerate() { if i > 0 { diff --git a/vortex-array/src/scalar/tests/casting.rs b/vortex-array/src/scalar/tests/casting.rs index b73d4c83818..ae63232330b 100644 --- a/vortex-array/src/scalar/tests/casting.rs +++ b/vortex-array/src/scalar/tests/casting.rs @@ -152,7 +152,7 @@ mod tests { Some(ScalarValue::Primitive(PValue::F32(f32_value))), ]; - let scalar = Scalar::new(struct_dtype, Some(ScalarValue::List(field_values))); + let scalar = Scalar::new(struct_dtype, Some(ScalarValue::Tuple(field_values))); let struct_scalar = scalar.as_struct(); let fields: Vec<_> = (0..3) @@ -209,7 +209,7 @@ mod tests { ))), ]; - let scalar = Scalar::new(list_dtype, Some(ScalarValue::List(elements))); + let scalar = Scalar::new(list_dtype, Some(ScalarValue::Tuple(elements))); let list_scalar = scalar.as_list(); let elements = list_scalar.elements().unwrap(); @@ -353,7 +353,7 @@ mod tests { let scalar = Scalar::new( DType::Extension(ext_dtype.erased()), - Some(ScalarValue::List(field_values)), + Some(ScalarValue::Tuple(field_values)), ); // Verify the struct field was coerced diff --git a/vortex-array/src/scalar/tests/nested.rs b/vortex-array/src/scalar/tests/nested.rs index 0aadd4ce2c9..d02bf43c631 100644 --- a/vortex-array/src/scalar/tests/nested.rs +++ b/vortex-array/src/scalar/tests/nested.rs @@ -311,7 +311,7 @@ mod tests { Arc::from(DType::Primitive(PType::U16, Nullability::Nullable)), Nullability::Nullable, ), - Some(ScalarValue::List(vec![ + Some(ScalarValue::Tuple(vec![ Some(ScalarValue::Primitive(PValue::U16(6))), Some(ScalarValue::Primitive(PValue::U16(100))), ])), @@ -350,7 +350,7 @@ mod tests { Arc::from(DType::Primitive(PType::U16, Nullability::Nullable)), Nullability::Nullable, ), - Some(ScalarValue::List(vec![ + Some(ScalarValue::Tuple(vec![ Some(ScalarValue::Primitive(PValue::U16(100))), Some(ScalarValue::Primitive(PValue::U16(256))), // Too large for U8 Some(ScalarValue::Primitive(PValue::U16(1000))), // Too large for U8 diff --git a/vortex-array/src/scalar/tests/nullability.rs b/vortex-array/src/scalar/tests/nullability.rs index 4d2bff418a5..d862d08d837 100644 --- a/vortex-array/src/scalar/tests/nullability.rs +++ b/vortex-array/src/scalar/tests/nullability.rs @@ -54,7 +54,7 @@ mod tests { Arc::from(DType::Primitive(PType::U16, Nullability::Nullable)), Nullability::Nullable, ), - Some(ScalarValue::List(vec![Some(ScalarValue::Primitive( + Some(ScalarValue::Tuple(vec![Some(ScalarValue::Primitive( PValue::U16(6), ))])), ); @@ -97,7 +97,7 @@ mod tests { Arc::from(DType::Primitive(PType::U16, Nullability::Nullable)), Nullability::Nullable, ), - Some(ScalarValue::List(vec![ + Some(ScalarValue::Tuple(vec![ Some(ScalarValue::Primitive(PValue::U16(6))), None, Some(ScalarValue::Primitive(PValue::U16(10))), @@ -200,7 +200,7 @@ mod tests { Arc::from(DType::Primitive(PType::U16, Nullability::Nullable)), Nullability::Nullable, ), - Some(ScalarValue::List(vec![ + Some(ScalarValue::Tuple(vec![ Some(ScalarValue::Primitive(PValue::U16(6))), None, ])), diff --git a/vortex-array/src/scalar/typed_view/binary.rs b/vortex-array/src/scalar/typed_view/binary.rs index 9235d4e17ef..cb107e3613c 100644 --- a/vortex-array/src/scalar/typed_view/binary.rs +++ b/vortex-array/src/scalar/typed_view/binary.rs @@ -20,7 +20,7 @@ use crate::scalar::ScalarValue; /// /// This type provides a view into a binary scalar value, which can be either /// a valid byte buffer or null. -#[derive(Debug, Clone, Hash)] +#[derive(Debug, Clone, Copy, Hash)] pub struct BinaryScalar<'a> { /// The data type of this scalar. dtype: &'a DType, diff --git a/vortex-array/src/scalar/typed_view/bool.rs b/vortex-array/src/scalar/typed_view/bool.rs index 10f8cd47d9f..c971d1169c6 100644 --- a/vortex-array/src/scalar/typed_view/bool.rs +++ b/vortex-array/src/scalar/typed_view/bool.rs @@ -19,7 +19,7 @@ use crate::scalar::ScalarValue; /// /// This type provides a view into a boolean scalar value, which can be either /// true, false, or null. -#[derive(Debug, Clone, Hash, Eq)] +#[derive(Debug, Clone, Copy, Hash, Eq)] pub struct BoolScalar<'a> { /// The data type of this scalar. dtype: &'a DType, diff --git a/vortex-array/src/scalar/typed_view/extension/mod.rs b/vortex-array/src/scalar/typed_view/extension/mod.rs index dfbc25f936d..3508883fc92 100644 --- a/vortex-array/src/scalar/typed_view/extension/mod.rs +++ b/vortex-array/src/scalar/typed_view/extension/mod.rs @@ -19,7 +19,7 @@ use crate::scalar::ScalarValue; /// A scalar value representing an extension type. /// /// Extension types allow wrapping a storage type with custom semantics. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct ExtScalar<'a> { /// A reference to the `DType` of the extension type. This **must** be the [`DType::Extension`] /// variant. diff --git a/vortex-array/src/scalar/typed_view/list.rs b/vortex-array/src/scalar/typed_view/list.rs index 3a158dd59ca..15de731089a 100644 --- a/vortex-array/src/scalar/typed_view/list.rs +++ b/vortex-array/src/scalar/typed_view/list.rs @@ -29,7 +29,7 @@ use crate::scalar::ScalarValue; /// number of `elements` is equal to the `size` field of the [`FixedSizeList`]. /// /// [`FixedSizeList`]: DType::FixedSizeList -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct ListScalar<'a> { /// The data type of this scalar. dtype: &'a DType, @@ -207,7 +207,7 @@ impl<'a> ListScalar<'a> { Scalar::try_new( dtype.clone(), - Some(ScalarValue::List( + Some(ScalarValue::Tuple( self.elements .ok_or_else(|| vortex_err!("nullness should be handled in Scalar::cast"))? .iter() diff --git a/vortex-array/src/scalar/typed_view/struct_.rs b/vortex-array/src/scalar/typed_view/struct_.rs index 93b796f055f..d8069bab77c 100644 --- a/vortex-array/src/scalar/typed_view/struct_.rs +++ b/vortex-array/src/scalar/typed_view/struct_.rs @@ -27,7 +27,7 @@ use crate::scalar::ScalarValue; /// /// This type provides a view into a struct scalar value, which can contain /// named fields with different types, or be null. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct StructScalar<'a> { /// The data type of this scalar. dtype: &'a DType, @@ -236,7 +236,7 @@ impl<'a> StructScalar<'a> { .map(|s| s.into_value()) }) .collect::>>()?; - Scalar::try_new(dtype.clone(), Some(ScalarValue::List(fields))) + Scalar::try_new(dtype.clone(), Some(ScalarValue::Tuple(fields))) } else { Ok(Scalar::null(dtype.clone())) } @@ -261,7 +261,7 @@ impl<'a> StructScalar<'a> { return Ok(Scalar::null(projected_dtype)); }; - let new_fields = ScalarValue::List( + let new_fields = ScalarValue::Tuple( projection .iter() .map(|name| { @@ -306,7 +306,7 @@ impl Scalar { } let value_children: Vec<_> = children.into_iter().map(|x| x.into_value()).collect(); - Self::try_new(dtype, Some(ScalarValue::List(value_children))) + Self::try_new(dtype, Some(ScalarValue::Tuple(value_children))) .vortex_expect("unable to construct a struct `Scalar`") } @@ -323,7 +323,7 @@ impl Scalar { children: impl IntoIterator, ) -> Self { let value_children: Vec<_> = children.into_iter().map(|s| s.into_value()).collect(); - unsafe { Self::new_unchecked(dtype, Some(ScalarValue::List(value_children))) } + unsafe { Self::new_unchecked(dtype, Some(ScalarValue::Tuple(value_children))) } } } diff --git a/vortex-array/src/scalar/typed_view/utf8.rs b/vortex-array/src/scalar/typed_view/utf8.rs index acf0ab9f407..5a9ad84064b 100644 --- a/vortex-array/src/scalar/typed_view/utf8.rs +++ b/vortex-array/src/scalar/typed_view/utf8.rs @@ -22,7 +22,7 @@ use crate::scalar::ScalarValue; /// /// This type provides a view into a UTF-8 string scalar value, which can be either /// a valid UTF-8 string or null. -#[derive(Debug, Clone, Hash, Eq)] +#[derive(Debug, Clone, Copy, Hash, Eq)] pub struct Utf8Scalar<'a> { /// The data type of this scalar. dtype: &'a DType, diff --git a/vortex-array/src/scalar/validate.rs b/vortex-array/src/scalar/validate.rs index 2696dc1f804..4df38187a9a 100644 --- a/vortex-array/src/scalar/validate.rs +++ b/vortex-array/src/scalar/validate.rs @@ -74,8 +74,8 @@ impl Scalar { ); } DType::List(elem_dtype, _) => { - let ScalarValue::List(elements) = value else { - vortex_bail!("list dtype expected List value, got {value}"); + let ScalarValue::Tuple(elements) = value else { + vortex_bail!("list dtype expected Tuple value, got {value}"); }; for (i, element) in elements.iter().enumerate() { @@ -84,8 +84,8 @@ impl Scalar { } } DType::FixedSizeList(elem_dtype, size, _) => { - let ScalarValue::List(elements) = value else { - vortex_bail!("fixed-size list dtype expected List value, got {value}",); + let ScalarValue::Tuple(elements) = value else { + vortex_bail!("fixed-size list dtype expected Tuple value, got {value}",); }; let len = elements.len(); @@ -102,8 +102,8 @@ impl Scalar { } } DType::Struct(fields, _) => { - let ScalarValue::List(values) = value else { - vortex_bail!("struct dtype expected List value, got {value}"); + let ScalarValue::Tuple(values) = value else { + vortex_bail!("struct dtype expected Tuple value, got {value}"); }; let nfields = fields.nfields(); diff --git a/vortex-array/src/scalar_fn/fns/is_not_null.rs b/vortex-array/src/scalar_fn/fns/is_not_null.rs index f5449a20cad..26e474cc447 100644 --- a/vortex-array/src/scalar_fn/fns/is_not_null.rs +++ b/vortex-array/src/scalar_fn/fns/is_not_null.rs @@ -3,6 +3,7 @@ use std::fmt::Formatter; +use vortex_array::scalar_fn::internal::row_count::RowCount; use vortex_error::VortexResult; use vortex_session::VortexSession; @@ -14,10 +15,7 @@ use crate::dtype::DType; use crate::dtype::Nullability; use crate::expr::Expression; use crate::expr::StatsCatalog; -use crate::expr::and; use crate::expr::eq; -use crate::expr::gt; -use crate::expr::lit; use crate::expr::stats::Stat; use crate::scalar_fn::Arity; use crate::scalar_fn::ChildName; @@ -25,6 +23,7 @@ use crate::scalar_fn::EmptyOptions; use crate::scalar_fn::ExecutionArgs; use crate::scalar_fn::ScalarFnId; use crate::scalar_fn::ScalarFnVTable; +use crate::scalar_fn::ScalarFnVTableExt; use crate::validity::Validity; /// Expression that checks for non-null values. @@ -106,20 +105,10 @@ impl ScalarFnVTable for IsNotNull { expr: &Expression, catalog: &dyn StatsCatalog, ) -> Option { - // is_not_null is falsified when ALL values are null, i.e. null_count == len. - // Since there is no len stat in the zone map, we approximate using IsConstant: - // if the zone is constant and has any nulls, then all values must be null. - // - // TODO(#7187): Add a len stat to enable the more general falsification: - // null_count == len => is_not_null is all false. - let null_count_expr = expr.child(0).stat_expression(Stat::NullCount, catalog)?; - let is_constant_expr = expr.child(0).stat_expression(Stat::IsConstant, catalog)?; - // If the zone is constant (is_constant == true) and has nulls (null_count > 0), - // then all values must be null, so is_not_null is all false. - Some(and( - eq(is_constant_expr, lit(true)), - gt(null_count_expr, lit(0u64)), - )) + // is_not_null is falsified when ALL values are null, i.e. null_count == row_count. + let child = expr.child(0); + let null_count_expr = child.stat_expression(Stat::NullCount, catalog)?; + Some(eq(null_count_expr, RowCount.new_expr(EmptyOptions, []))) } } @@ -127,6 +116,8 @@ impl ScalarFnVTable for IsNotNull { mod tests { use vortex_buffer::buffer; use vortex_error::VortexExpect as _; + use vortex_utils::aliases::hash_map::HashMap; + use vortex_utils::aliases::hash_set::HashSet; use crate::IntoArray; use crate::LEGACY_SESSION; @@ -134,12 +125,22 @@ mod tests { use crate::arrays::PrimitiveArray; use crate::arrays::StructArray; use crate::dtype::DType; + use crate::dtype::Field; + use crate::dtype::FieldPath; + use crate::dtype::FieldPathSet; use crate::dtype::Nullability; + use crate::expr::col; + use crate::expr::eq; use crate::expr::get_item; use crate::expr::is_not_null; + use crate::expr::pruning::checked_pruning_expr; use crate::expr::root; + use crate::expr::stats::Stat; use crate::expr::test_harness; use crate::scalar::Scalar; + use crate::scalar_fn::EmptyOptions; + use crate::scalar_fn::internal::row_count::RowCount; + use crate::scalar_fn::vtable::ScalarFnVTableExt; #[test] fn dtype() { @@ -255,50 +256,29 @@ mod tests { #[test] fn test_is_not_null_sensitive() { - use crate::expr::col; assert!(is_not_null(col("a")).signature().is_null_sensitive()); } #[test] fn test_is_not_null_falsification() { - use vortex_utils::aliases::hash_map::HashMap; - use vortex_utils::aliases::hash_set::HashSet; - - use crate::dtype::Field; - use crate::dtype::FieldPath; - use crate::dtype::FieldPathSet; - use crate::expr::and; - use crate::expr::col; - use crate::expr::eq; - use crate::expr::gt; - use crate::expr::lit; - use crate::expr::pruning::checked_pruning_expr; - use crate::expr::stats::Stat; - let expr = is_not_null(col("a")); let (pruning_expr, st) = checked_pruning_expr( &expr, - &FieldPathSet::from_iter([ - FieldPath::from_iter([Field::Name("a".into()), Field::Name("null_count".into())]), - FieldPath::from_iter([Field::Name("a".into()), Field::Name("is_constant".into())]), - ]), + &FieldPathSet::from_iter([FieldPath::from_iter([ + Field::Name("a".into()), + Field::Name("null_count".into()), + ])]), ) .unwrap(); assert_eq!( &pruning_expr, - &and( - eq(col("a_is_constant"), lit(true)), - gt(col("a_null_count"), lit(0u64)), - ) + &eq(col("a_null_count"), RowCount.new_expr(EmptyOptions, [])) ); assert_eq!( st.map(), - &HashMap::from_iter([( - FieldPath::from_name("a"), - HashSet::from([Stat::NullCount, Stat::IsConstant]) - )]) + &HashMap::from_iter([(FieldPath::from_name("a"), HashSet::from([Stat::NullCount]))]) ); } } diff --git a/vortex-array/src/scalar_fn/fns/mask/mod.rs b/vortex-array/src/scalar_fn/fns/mask/mod.rs index cce76412fa6..7e45d2e40ee 100644 --- a/vortex-array/src/scalar_fn/fns/mask/mod.rs +++ b/vortex-array/src/scalar_fn/fns/mask/mod.rs @@ -14,12 +14,11 @@ use crate::ArrayRef; use crate::Canonical; use crate::ExecutionCtx; use crate::IntoArray; -use crate::arrays::BoolArray; use crate::arrays::Constant; use crate::arrays::ConstantArray; -use crate::arrays::bool::BoolArrayExt; use crate::arrays::masked::mask_validity_canonical; use crate::builtins::ArrayBuiltins; +use crate::child_to_validity; use crate::dtype::DType; use crate::dtype::Nullability; use crate::expr::Expression; @@ -182,11 +181,9 @@ fn execute_canonical( mask_array: ArrayRef, ctx: &mut ExecutionCtx, ) -> VortexResult { - let mask_bool = mask_array.execute::(ctx)?; - let validity_mask = vortex_mask::Mask::from(mask_bool.to_bit_buffer()); - + let validity = child_to_validity(&Some(mask_array), Nullability::Nullable); let canonical = input.execute::(ctx)?; - Ok(mask_validity_canonical(canonical, &validity_mask, ctx)?.into_array()) + Ok(mask_validity_canonical(canonical, validity, ctx)?.into_array()) } #[cfg(test)] diff --git a/vortex-array/src/scalar_fn/internal/mod.rs b/vortex-array/src/scalar_fn/internal/mod.rs new file mode 100644 index 00000000000..c91a7541c8a --- /dev/null +++ b/vortex-array/src/scalar_fn/internal/mod.rs @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +pub mod row_count; diff --git a/vortex-array/src/scalar_fn/internal/row_count.rs b/vortex-array/src/scalar_fn/internal/row_count.rs new file mode 100644 index 00000000000..f411626321d --- /dev/null +++ b/vortex-array/src/scalar_fn/internal/row_count.rs @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use std::fmt::Formatter; + +use vortex_array::ArrayRef; +use vortex_array::ExecutionCtx; +use vortex_array::arrays::ScalarFn; +use vortex_array::arrays::scalar_fn::ExactScalarFn; +use vortex_array::arrays::scalar_fn::ScalarFnArrayExt; +use vortex_array::dtype::DType; +use vortex_array::dtype::Nullability; +use vortex_array::dtype::PType; +use vortex_array::expr::Expression; +use vortex_array::scalar_fn::Arity; +use vortex_array::scalar_fn::ChildName; +use vortex_array::scalar_fn::EmptyOptions; +use vortex_array::scalar_fn::ExecutionArgs; +use vortex_array::scalar_fn::ScalarFnId; +use vortex_array::scalar_fn::ScalarFnVTable; +use vortex_error::VortexResult; +use vortex_error::vortex_bail; +use vortex_error::vortex_ensure; + +/// Zero-argument placeholder for the row count of the current evaluation scope. +/// +/// This expression *MUST* be replaced with a concrete array before evaluation. +/// Currently, the rewrite only happens in the context of stats pruning. +/// +/// `RowCount` is emitted while building pruning predicates that need a +/// scope-level value which is not stored as a regular stats column, such as the +/// row count of the current file or zone. The layer that owns that scope must +/// replace each placeholder with a concrete array via [`substitute_row_count`] +/// before evaluation. +/// +/// Calling [`ScalarFnVTable::execute`] directly returns an error because this +/// node is only a marker in a lazy expression tree. +#[derive(Clone)] +pub struct RowCount; + +impl ScalarFnVTable for RowCount { + type Options = EmptyOptions; + + fn id(&self) -> ScalarFnId { + ScalarFnId::from("vortex.row_count") + } + + fn arity(&self, _options: &Self::Options) -> Arity { + Arity::Exact(0) + } + + fn child_name(&self, _options: &Self::Options, _child_idx: usize) -> ChildName { + unreachable!("RowCount has arity 0") + } + + fn fmt_sql( + &self, + _options: &Self::Options, + _expr: &Expression, + f: &mut Formatter<'_>, + ) -> std::fmt::Result { + write!(f, "row_count()") + } + + fn return_dtype(&self, _options: &Self::Options, _args: &[DType]) -> VortexResult { + Ok(DType::Primitive(PType::U64, Nullability::NonNullable)) + } + + fn execute( + &self, + _options: &Self::Options, + _args: &dyn ExecutionArgs, + _ctx: &mut ExecutionCtx, + ) -> VortexResult { + vortex_bail!("RowCount must be substituted before evaluation") + } + + fn is_null_sensitive(&self, _options: &Self::Options) -> bool { + false + } + + fn is_fallible(&self, _options: &Self::Options) -> bool { + false + } +} + +/// Returns whether `array` contains a [`RowCount`] placeholder. +/// +/// Traversal is limited to lazy [`ScalarFnArray`] nodes produced by +/// [`ArrayRef::apply`][crate::ArrayRef::apply]. Other arrays are evaluation +/// leaves and cannot contain unevaluated placeholders. +/// +/// [`ScalarFnArray`]: vortex_array::arrays::ScalarFnArray +pub fn contains_row_count(array: &ArrayRef) -> bool { + if array.is::>() { + return true; + } + match array.as_opt::() { + Some(view) => view.iter_children().any(contains_row_count), + None => false, + } +} + +/// Replaces every [`RowCount`] placeholder with `replacement`. +/// +/// The replacement must have the same dtype and length as each placeholder. +/// Lazy [`ScalarFnArray`] ancestors are rewritten through slot take/put so +/// unaffected children are preserved, while non-[`ScalarFn`] arrays are returned +/// unchanged. +/// +/// [`ScalarFnArray`]: vortex_array::arrays::ScalarFnArray +pub fn substitute_row_count(array: ArrayRef, replacement: &ArrayRef) -> VortexResult { + if array.is::>() { + vortex_ensure!( + replacement.len() == array.len(), + "RowCount replacement length {} does not match scope length {}", + replacement.len(), + array.len(), + ); + vortex_ensure!( + replacement.dtype() == array.dtype(), + "RowCount replacement dtype {} does not match scope dtype {}", + replacement.dtype(), + array.dtype(), + ); + return Ok(replacement.clone()); + } + + if !array.is::() { + return Ok(array); + } + + let nchildren = array.nchildren(); + let mut array = array; + for slot_idx in 0..nchildren { + // SAFETY: `substitute_row_count` always returns an array with the same dtype and + // length as its input — `RowCount` placeholders are replaced with a checked + // replacement (same dtype and length), and `ScalarFn` recursion preserves both by + // operating on each slot in place. + let (taken, child) = unsafe { array.take_slot_unchecked(slot_idx)? }; + let new_child = substitute_row_count(child, replacement)?; + array = unsafe { taken.put_slot_unchecked(slot_idx, new_child)? }; + } + Ok(array) +} + +#[cfg(test)] +mod tests { + use vortex_array::dtype::DType; + use vortex_array::dtype::Nullability; + use vortex_array::dtype::PType; + + use crate::scalar_fn::EmptyOptions; + use crate::scalar_fn::internal::row_count::RowCount; + use crate::scalar_fn::vtable::ScalarFnVTableExt; + + #[test] + fn row_count_helper_dtype() { + let expr = RowCount.new_expr(EmptyOptions, []); + assert_eq!( + expr.return_dtype(&DType::Primitive(PType::I32, Nullability::Nullable)) + .unwrap(), + DType::Primitive(PType::U64, Nullability::NonNullable), + ); + } +} diff --git a/vortex-array/src/scalar_fn/mod.rs b/vortex-array/src/scalar_fn/mod.rs index 6f8ba1b6544..590ccb44224 100644 --- a/vortex-array/src/scalar_fn/mod.rs +++ b/vortex-array/src/scalar_fn/mod.rs @@ -31,6 +31,7 @@ mod signature; pub use signature::*; pub mod fns; +pub mod internal; pub mod session; /// A unique identifier for a scalar function. diff --git a/vortex-array/src/scalar_fn/session.rs b/vortex-array/src/scalar_fn/session.rs index 3c78f56928d..32783e9df89 100644 --- a/vortex-array/src/scalar_fn/session.rs +++ b/vortex-array/src/scalar_fn/session.rs @@ -1,10 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::any::Any; use std::sync::Arc; use vortex_session::Ref; use vortex_session::SessionExt; +use vortex_session::SessionVar; use vortex_session::registry::Registry; use crate::scalar_fn::ScalarFnPluginRef; @@ -74,6 +76,16 @@ impl Default for ScalarFnSession { } } +impl SessionVar for ScalarFnSession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Extension trait for accessing scalar function session data. pub trait ScalarFnSessionExt: SessionExt { /// Returns the scalar function vtable registry. diff --git a/vortex-array/src/session/mod.rs b/vortex-array/src/session/mod.rs index 4b30257d981..98a7417722b 100644 --- a/vortex-array/src/session/mod.rs +++ b/vortex-array/src/session/mod.rs @@ -1,12 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::any::Any; use std::sync::Arc; use vortex_error::VortexResult; use vortex_error::vortex_bail; use vortex_session::Ref; use vortex_session::SessionExt; +use vortex_session::SessionVar; use vortex_session::registry::Registry; use crate::ArrayRef; @@ -85,6 +87,16 @@ impl Default for ArraySession { } } +impl SessionVar for ArraySession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Session data for Vortex arrays. pub trait ArraySessionExt: SessionExt { /// Returns the array encoding registry. diff --git a/vortex-bench/src/clickbench/benchmark.rs b/vortex-bench/src/clickbench/benchmark.rs index 9cfafb8832e..a68ce0b54e8 100644 --- a/vortex-bench/src/clickbench/benchmark.rs +++ b/vortex-bench/src/clickbench/benchmark.rs @@ -28,7 +28,7 @@ impl ClickBenchBenchmark { queries_file: Option, use_remote_data_dir: Option, ) -> Result { - let url = Self::create_data_url(&use_remote_data_dir, flavor)?; + let url = Self::create_data_url(use_remote_data_dir.as_deref(), flavor)?; Ok(Self { flavor, queries_file, @@ -36,8 +36,8 @@ impl ClickBenchBenchmark { }) } - fn create_data_url(remote_data_dir: &Option, flavor: Flavor) -> Result { - resolve_data_url(remote_data_dir.as_deref(), &format!("clickbench_{flavor}")) + fn create_data_url(remote_data_dir: Option<&str>, flavor: Flavor) -> Result { + resolve_data_url(remote_data_dir, &format!("clickbench_{flavor}")) } } diff --git a/vortex-bench/src/fineweb/mod.rs b/vortex-bench/src/fineweb/mod.rs index 5acb57f64e9..93151cc6fca 100644 --- a/vortex-bench/src/fineweb/mod.rs +++ b/vortex-bench/src/fineweb/mod.rs @@ -50,12 +50,12 @@ impl FinewebBenchmark { } pub fn with_remote_data_dir(use_remote_data_dir: Option) -> anyhow::Result { - let data_url = Self::create_data_url(&use_remote_data_dir)?; + let data_url = Self::create_data_url(use_remote_data_dir.as_deref())?; Ok(Self { data_url }) } - fn create_data_url(remote_data_dir: &Option) -> anyhow::Result { - resolve_data_url(remote_data_dir.as_deref(), "fineweb") + fn create_data_url(remote_data_dir: Option<&str>) -> anyhow::Result { + resolve_data_url(remote_data_dir, "fineweb") } } diff --git a/vortex-bench/src/realnest/gharchive.rs b/vortex-bench/src/realnest/gharchive.rs index 86b981a9fbe..3ec6a67f340 100644 --- a/vortex-bench/src/realnest/gharchive.rs +++ b/vortex-bench/src/realnest/gharchive.rs @@ -43,12 +43,12 @@ impl GithubArchiveBenchmark { } pub fn with_remote_data_dir(use_remote_data_dir: Option) -> anyhow::Result { - let data_url = Self::create_data_url(&use_remote_data_dir)?; + let data_url = Self::create_data_url(use_remote_data_dir.as_deref())?; Ok(Self { data_url }) } - fn create_data_url(remote_data_dir: &Option) -> anyhow::Result { - resolve_data_url(remote_data_dir.as_deref(), "gharchive") + fn create_data_url(remote_data_dir: Option<&str>) -> anyhow::Result { + resolve_data_url(remote_data_dir, "gharchive") } } diff --git a/vortex-bench/src/tpcds/tpcds_benchmark.rs b/vortex-bench/src/tpcds/tpcds_benchmark.rs index d44b3645c57..7f8f2d5281e 100644 --- a/vortex-bench/src/tpcds/tpcds_benchmark.rs +++ b/vortex-bench/src/tpcds/tpcds_benchmark.rs @@ -27,11 +27,11 @@ impl TpcDsBenchmark { pub fn new(scale_factor: String, use_remote_data_dir: Option) -> Result { Ok(Self { scale_factor: scale_factor.clone(), - data_url: Self::create_data_url(&use_remote_data_dir, &scale_factor)?, + data_url: Self::create_data_url(use_remote_data_dir.as_deref(), &scale_factor)?, }) } - fn create_data_url(remote_data_dir: &Option, scale_factor: &str) -> Result { + fn create_data_url(remote_data_dir: Option<&str>, scale_factor: &str) -> Result { match remote_data_dir { None => { let data_dir = "tpcds".to_data_path(); diff --git a/vortex-bench/src/tpch/benchmark.rs b/vortex-bench/src/tpch/benchmark.rs index c9d85f2be9b..6851e5f5f06 100644 --- a/vortex-bench/src/tpch/benchmark.rs +++ b/vortex-bench/src/tpch/benchmark.rs @@ -37,14 +37,11 @@ impl TpcHBenchmark { pub fn new(scale_factor: String, use_remote_data_dir: Option) -> anyhow::Result { Ok(Self { scale_factor: scale_factor.clone(), - data_url: Self::create_data_url(&use_remote_data_dir, &scale_factor)?, + data_url: Self::create_data_url(use_remote_data_dir.as_deref(), &scale_factor)?, }) } - fn create_data_url( - remote_data_dir: &Option, - scale_factor: &str, - ) -> anyhow::Result { + fn create_data_url(remote_data_dir: Option<&str>, scale_factor: &str) -> anyhow::Result { match remote_data_dir { None => { let data_dir = "tpch".to_data_path(); diff --git a/vortex-compressor/src/compressor.rs b/vortex-compressor/src/compressor.rs index b99d31c6d73..d3ad0d9d5c3 100644 --- a/vortex-compressor/src/compressor.rs +++ b/vortex-compressor/src/compressor.rs @@ -381,7 +381,7 @@ impl CascadingCompressor { CompressionEstimate::Verdict(EstimateVerdict::Ratio(ratio)) => { let score = EstimateScore::FiniteCompression(ratio); - if is_better_score(score, &best) { + if is_better_score(score, best.as_ref()) { best = Some((scheme, score)); } } @@ -407,7 +407,7 @@ impl CascadingCompressor { exec_ctx, )?; - if is_better_score(score, &best) { + if is_better_score(score, best.as_ref()) { best = Some((scheme, score)); } } @@ -420,7 +420,7 @@ impl CascadingCompressor { EstimateVerdict::Ratio(ratio) => { let score = EstimateScore::FiniteCompression(ratio); - if is_better_score(score, &best) { + if is_better_score(score, best.as_ref()) { best = Some((scheme, score)); } } diff --git a/vortex-compressor/src/estimate.rs b/vortex-compressor/src/estimate.rs index 065937ffac9..70dd75d13b0 100644 --- a/vortex-compressor/src/estimate.rs +++ b/vortex-compressor/src/estimate.rs @@ -182,9 +182,9 @@ impl WinnerEstimate { /// Returns `true` if `score` beats the current best estimate. pub(super) fn is_better_score( score: EstimateScore, - best: &Option<(&'static dyn Scheme, EstimateScore)>, + best: Option<&(&'static dyn Scheme, EstimateScore)>, ) -> bool { - score.is_valid() && best.is_none_or(|(_, best_score)| score.beats(best_score)) + score.is_valid() && best.is_none_or(|(_, best_score)| score.beats(*best_score)) } /// Estimates compression ratio by compressing a ~1% sample of the data. diff --git a/vortex-cuda/benches/dict_cuda.rs b/vortex-cuda/benches/dict_cuda.rs index 4f1b72a49e3..a7371f3b3ad 100644 --- a/vortex-cuda/benches/dict_cuda.rs +++ b/vortex-cuda/benches/dict_cuda.rs @@ -8,6 +8,7 @@ mod common; +use std::fmt::Debug; use std::mem::size_of; use std::sync::Arc; use std::sync::atomic::Ordering; @@ -48,7 +49,7 @@ fn make_dict_array_typed(len: usize, dict_size: usize) -> DictArray where V: NativePType + From, C: NativePType + TryFrom, - >::Error: std::fmt::Debug, + >::Error: Debug, { // Dictionary values let values: Vec = (0..dict_size) @@ -71,7 +72,7 @@ fn benchmark_dict_typed(c: &mut Criterion, config: &DictBenchConfig) where V: NativePType + DeviceRepr + From, C: NativePType + DeviceRepr + TryFrom, - >::Error: std::fmt::Debug, + >::Error: Debug, { let mut group = c.benchmark_group("dict_cuda"); diff --git a/vortex-cuda/benches/dynamic_dispatch_cuda.rs b/vortex-cuda/benches/dynamic_dispatch_cuda.rs index 4a5ea461d02..f4b8a4e392b 100644 --- a/vortex-cuda/benches/dynamic_dispatch_cuda.rs +++ b/vortex-cuda/benches/dynamic_dispatch_cuda.rs @@ -5,6 +5,7 @@ #![expect(clippy::cast_possible_truncation)] #![expect(clippy::expect_used)] +use std::marker::PhantomData; use std::mem::size_of; use std::sync::Arc; use std::time::Duration; @@ -14,19 +15,22 @@ use criterion::Criterion; use criterion::Throughput; use cudarc::driver::CudaSlice; use cudarc::driver::DevicePtr; +use cudarc::driver::DeviceRepr; use cudarc::driver::LaunchConfig; use cudarc::driver::PushKernelArg; use cudarc::driver::sys::CUevent_flags; use futures::executor::block_on; +use vortex::array::ArrayRef; use vortex::array::IntoArray; use vortex::array::LEGACY_SESSION; use vortex::array::VortexSessionExecute; use vortex::array::arrays::DictArray; use vortex::array::arrays::PrimitiveArray; +use vortex::array::buffer; use vortex::array::scalar::Scalar; use vortex::array::validity::Validity::NonNullable; use vortex::buffer::Buffer; -use vortex::dtype::PType; +use vortex::dtype::NativePType; use vortex::encodings::alp::ALP; use vortex::encodings::alp::ALPArrayExt; use vortex::encodings::alp::ALPArraySlotsExt; @@ -43,6 +47,7 @@ use vortex::error::VortexResult; use vortex::error::vortex_err; use vortex::session::VortexSession; use vortex_cuda::CudaDeviceBuffer; +use vortex_cuda::CudaDispatchMode; use vortex_cuda::CudaExecutionCtx; use vortex_cuda::CudaSession; use vortex_cuda::dynamic_dispatch::CudaDispatchPlan; @@ -58,16 +63,16 @@ const BENCH_ARGS: &[(usize, &str)] = &[(10_000_000, "10M"), (100_000_000, "100M" /// This deliberately does not use `CudaDispatchPlan::execute` because the /// benchmark pre-allocates the output buffer and device plan once, then reuses /// them across iterations. -fn run_timed( +fn run_timed( cuda_ctx: &mut CudaExecutionCtx, array_len: usize, output_buf: &CudaDeviceBuffer, device_plan: &Arc>, shared_mem_bytes: u32, ) -> VortexResult { - let cuda_function = cuda_ctx.load_function("dynamic_dispatch", &[PType::U32])?; + let cuda_function = cuda_ctx.load_function("dynamic_dispatch", &[T::PTYPE])?; let array_len_u64 = array_len as u64; - let output_view = output_buf.as_view::(); + let output_view = output_buf.as_view::(); let (output_ptr, record_output) = output_view.device_ptr(cuda_ctx.stream()); let (plan_ptr, record_plan) = device_plan.device_ptr(cuda_ctx.stream()); @@ -114,18 +119,24 @@ fn run_timed( } /// Benchmark runner: builds a dynamic plan and launches the kernel. -struct BenchRunner { +/// +/// `T` is the unsigned integer type matching the output element width +/// (e.g. `u32` for f32/i32/u32, `u64` for f64/i64/u64). +struct BenchRunner { _plan: CudaDispatchPlan, smem_bytes: u32, len: usize, device_plan: Arc>, output_buf: CudaDeviceBuffer, - _plan_buffers: Vec, + _plan_buffers: Vec, + _phantom: PhantomData, } -impl BenchRunner { - fn new(array: &vortex::array::ArrayRef, len: usize, cuda_ctx: &mut CudaExecutionCtx) -> Self { - let plan = match DispatchPlan::new(array).vortex_expect("build_dyn_dispatch_plan") { +impl BenchRunner { + fn new(array: &ArrayRef, len: usize, cuda_ctx: &mut CudaExecutionCtx) -> Self { + let plan = match DispatchPlan::new(array, CudaDispatchMode::DynDispatchOnly) + .vortex_expect("build_dyn_dispatch_plan") + { DispatchPlan::Fused(plan) => plan, _ => unreachable!("encoding not fusable"), }; @@ -150,16 +161,17 @@ impl BenchRunner { device_plan, output_buf: CudaDeviceBuffer::new( cuda_ctx - .device_alloc::(len.next_multiple_of(1024)) + .device_alloc::(len.next_multiple_of(1024)) .expect("alloc output"), ), _plan_buffers: device_buffers, + _phantom: PhantomData, } } fn run(&self, cuda_ctx: &mut CudaExecutionCtx) -> Duration { cuda_ctx.stream().synchronize().unwrap(); - run_timed( + run_timed::( cuda_ctx, self.len, &self.output_buf, @@ -202,7 +214,7 @@ fn bench_for_bitpacked(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -247,7 +259,7 @@ fn bench_dict_bp_codes(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -291,7 +303,72 @@ fn bench_runend(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); + + b.iter_custom(|iters| { + let mut total_time = Duration::ZERO; + for _ in 0..iters { + total_time += bench_runner.run(&mut cuda_ctx); + } + total_time + }); + }, + ); + } + + group.finish(); +} + +// --------------------------------------------------------------------------- +// Benchmark: ALP(FoR(BitPacked)) — f64 +// --------------------------------------------------------------------------- +fn bench_alp_for_bitpacked_f64(c: &mut Criterion) { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let mut group = c.benchmark_group("alp_for_bp_6bw_f64"); + + let exponents = Exponents { e: 2, f: 0 }; + let bit_width: u8 = 6; + + for (len, len_str) in BENCH_ARGS { + group.throughput(Throughput::Bytes((len * size_of::()) as u64)); + + // Generate f64 values that ALP-encode without patches. + let floats: Vec = (0..*len) + .map(|i| ::decode_single(10 + (i as i64 % 64), exponents)) + .collect(); + let float_prim = PrimitiveArray::new(Buffer::from(floats), NonNullable); + + // Encode: ALP → FoR → BitPacked + let alp = + alp_encode(float_prim.as_view(), Some(exponents), &mut ctx).vortex_expect("alp_encode"); + assert!(alp.patches().is_none()); + let for_arr = FoRData::encode( + alp.encoded() + .clone() + .execute::(&mut ctx) + .vortex_expect("to primitive"), + ) + .vortex_expect("for encode"); + let bp = BitPackedData::encode(for_arr.encoded(), bit_width, &mut ctx) + .vortex_expect("bitpack encode"); + + let tree = ALP::new( + FoR::try_new(bp.into_array(), for_arr.reference_scalar().clone()) + .vortex_expect("for_new") + .into_array(), + exponents, + None, + ); + let array = tree.into_array(); + + group.bench_with_input( + BenchmarkId::new("dynamic_dispatch_f64", len_str), + len, + |b, &n| { + let mut cuda_ctx = + CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); + + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -345,7 +422,7 @@ fn bench_dict_bp_codes_bp_for_values(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -410,7 +487,7 @@ fn bench_alp_for_bitpacked(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -457,7 +534,7 @@ fn bench_dict_bp_u8_codes_u32_values(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -500,7 +577,7 @@ fn bench_dict_bp_u16_codes_u32_values(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -543,7 +620,7 @@ fn bench_dict_bp_u32_codes_u32_values(c: &mut Criterion) { let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty()).vortex_expect("ctx"); - let bench_runner = BenchRunner::new(&array, n, &mut cuda_ctx); + let bench_runner = BenchRunner::::new(&array, n, &mut cuda_ctx); b.iter_custom(|iters| { let mut total_time = Duration::ZERO; @@ -565,6 +642,7 @@ fn benchmark_dynamic_dispatch(c: &mut Criterion) { bench_runend(c); bench_dict_bp_codes_bp_for_values(c); bench_alp_for_bitpacked(c); + bench_alp_for_bitpacked_f64(c); bench_dict_bp_u8_codes_u32_values(c); bench_dict_bp_u16_codes_u32_values(c); bench_dict_bp_u32_codes_u32_values(c); diff --git a/vortex-cuda/benches/filter_cuda.rs b/vortex-cuda/benches/filter_cuda.rs index b7647bfd814..3ea9b2433f6 100644 --- a/vortex-cuda/benches/filter_cuda.rs +++ b/vortex-cuda/benches/filter_cuda.rs @@ -18,6 +18,7 @@ use cudarc::driver::CudaSlice; use cudarc::driver::CudaView; use cudarc::driver::DevicePtr; use cudarc::driver::DevicePtrMut; +use cudarc::driver::DeviceRepr; use cudarc::driver::sys::CUevent_flags; use futures::executor::block_on; use vortex::error::VortexExpect; @@ -64,7 +65,7 @@ fn make_bitmask(len: usize, selectivity: f64) -> (Vec, usize) { /// Runs the CUB filter kernel and returns elapsed GPU time. #[expect(clippy::too_many_arguments)] -async fn run_filter_timed( +async fn run_filter_timed( d_input: CudaView<'_, T>, d_bitmask: CudaView<'_, u8>, d_output: &mut CudaSlice, @@ -132,14 +133,7 @@ async fn run_filter_timed( /// Benchmark filter for a specific type. fn benchmark_filter_type(c: &mut Criterion, type_name: &str) where - T: CubFilterable - + cudarc::driver::DeviceRepr - + From - + Debug - + Clone - + Send - + Sync - + 'static, + T: CubFilterable + DeviceRepr + From + Debug + Clone + Send + Sync + 'static, { let mut group = c.benchmark_group(format!("filter_cuda_{type_name}")); diff --git a/vortex-cuda/benches/runend_cuda.rs b/vortex-cuda/benches/runend_cuda.rs index 31c59037b0d..0b963a10698 100644 --- a/vortex-cuda/benches/runend_cuda.rs +++ b/vortex-cuda/benches/runend_cuda.rs @@ -18,6 +18,7 @@ use criterion::Criterion; use criterion::Throughput; use cudarc::driver::DeviceRepr; use futures::executor::block_on; +use vortex::array::ExecutionCtx; use vortex::array::IntoArray; use vortex::array::arrays::PrimitiveArray; use vortex::array::validity::Validity; @@ -37,7 +38,7 @@ use crate::common::TimedLaunchStrategy; fn make_runend_array_typed( output_len: usize, avg_run_len: usize, - ctx: &mut vortex::array::ExecutionCtx, + ctx: &mut ExecutionCtx, ) -> RunEndArray where T: NativePType + From, diff --git a/vortex-cuda/kernels/src/dynamic_dispatch.cu b/vortex-cuda/kernels/src/dynamic_dispatch.cu index b09f34ade81..0f2c4c157b9 100644 --- a/vortex-cuda/kernels/src/dynamic_dispatch.cu +++ b/vortex-cuda/kernels/src/dynamic_dispatch.cu @@ -140,11 +140,30 @@ scalar_op(T *values, const struct ScalarOp &op, char *__restrict smem, uint64_t break; } case ScalarOp::ALP: { - const float f = op.params.alp.f, e = op.params.alp.e; + if constexpr (sizeof(T) == 4) { + // The plan builder stores f32 F10/IF10 table entries as f64 + // in AlpParams. The round-trip f32→f64→f32 is exact per the + // C++ standard: [conv.fpprom] guarantees the widening is + // value-preserving, and [conv.double] guarantees the narrowing + // recovers the original value when it is exactly representable + // in the destination type (which it is, having originated as f32). + const float f = static_cast(op.params.alp.f); + const float e = static_cast(op.params.alp.e); #pragma unroll - for (uint32_t i = 0; i < N; ++i) { - float r = static_cast(static_cast(values[i])) * f * e; - values[i] = static_cast(__float_as_uint(r)); + for (uint32_t i = 0; i < N; ++i) { + float r = static_cast(static_cast(values[i])) * f * e; + values[i] = static_cast(__float_as_uint(r)); + } + } else if constexpr (sizeof(T) == 8) { + const double f = op.params.alp.f, e = op.params.alp.e; +#pragma unroll + for (uint32_t i = 0; i < N; ++i) { + double r = static_cast(static_cast(values[i])) * f * e; + // __double_as_longlong reinterprets f64 bits as int64, and + // static_cast to T (uint64_t) preserves the bit pattern + // under C++20's two's complement guarantee. + values[i] = static_cast(__double_as_longlong(r)); + } } // Apply ALP patches: override positions whose float value couldn't // be reconstructed through the ALP encode/decode cycle. diff --git a/vortex-cuda/kernels/src/dynamic_dispatch.h b/vortex-cuda/kernels/src/dynamic_dispatch.h index 2e51240ed4f..c4dbe55c9f3 100644 --- a/vortex-cuda/kernels/src/dynamic_dispatch.h +++ b/vortex-cuda/kernels/src/dynamic_dispatch.h @@ -20,7 +20,7 @@ /// /// Each source op and scalar op may produce a different PType than its input. /// For example, DICT transforms codes (e.g. u8) into values (e.g. f32), and -/// ALP transforms encoded integers (i32) into floats (f32). +/// ALP transforms encoded integers into floats (e.g. i32 → f32, i64 → f64). /// /// `PTypeTag` is a compact enum that identifies the primitive type at each /// point in the pipeline. The kernel uses it to dispatch typed memory @@ -171,7 +171,7 @@ struct SourceOp { /// Each scalar op declares its `output_ptype` — the PType of the values it /// produces. Most ops preserve the input type (FOR, ZIGZAG), but some /// change it: -/// - ALP: encoded int → float (e.g. i32 → f32) +/// - ALP: encoded int → float (e.g. i32 → f32, i64 → f64) /// - DICT: codes type → values type (e.g. u8 → u32) /// /// The plan builder uses `output_ptype` to determine the element width @@ -183,8 +183,8 @@ union ScalarParams { } frame_of_ref; struct AlpParams { - float f; - float e; + double f; + double e; uint64_t patches_ptr; // device pointer to GPUPatches struct (0 = none) } alp; diff --git a/vortex-cuda/src/arrow/canonical.rs b/vortex-cuda/src/arrow/canonical.rs index 7b5bfadd5ce..0ccace213c9 100644 --- a/vortex-cuda/src/arrow/canonical.rs +++ b/vortex-cuda/src/arrow/canonical.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::mem; +use std::ptr; + use async_trait::async_trait; use futures::future::BoxFuture; use vortex::array::ArrayRef; @@ -164,9 +167,9 @@ fn export_canonical( n_buffers: 2, buffers: private_data.buffer_ptrs.as_mut_ptr(), n_children: 0, - children: std::ptr::null_mut(), + children: ptr::null_mut(), release: Some(release_array), - dictionary: std::ptr::null_mut(), + dictionary: ptr::null_mut(), private_data: Box::into_raw(private_data).cast(), }; @@ -244,9 +247,9 @@ fn export_fixed_size( n_buffers: 2, buffers: private_data.buffer_ptrs.as_mut_ptr(), n_children: 0, - children: std::ptr::null_mut(), + children: ptr::null_mut(), release: Some(release_array), - dictionary: std::ptr::null_mut(), + dictionary: ptr::null_mut(), private_data: Box::into_raw(private_data).cast(), }; @@ -258,12 +261,11 @@ unsafe extern "C" fn release_array(array: *mut ArrowArray) { // code. This is necessary to ensure that the fields inside the CudaPrivateData // get dropped to free native/GPU memory. unsafe { - let private_data_ptr = - std::ptr::replace(&raw mut (*array).private_data, std::ptr::null_mut()); + let private_data_ptr = ptr::replace(&raw mut (*array).private_data, ptr::null_mut()); if !private_data_ptr.is_null() { let mut private_data = Box::from_raw(private_data_ptr.cast::()); - let children = std::mem::take(&mut private_data.children); + let children = mem::take(&mut private_data.children); for child in children { release_array(child); } @@ -277,6 +279,7 @@ unsafe extern "C" fn release_array(array: *mut ArrowArray) { #[cfg(test)] mod tests { use rstest::rstest; + use vortex::array::ArrayRef; use vortex::array::IntoArray; use vortex::array::arrays::DecimalArray; use vortex::array::arrays::NullArray; @@ -308,7 +311,7 @@ mod tests { #[case::f64(PrimitiveArray::from_iter([1.0f64, 2.0, 3.0]).into_array(), 3)] #[crate::test] async fn test_export_primitive( - #[case] array: vortex::array::ArrayRef, + #[case] array: ArrayRef, #[case] expected_len: i64, ) -> VortexResult<()> { let mut ctx = CudaSession::create_execution_ctx(&VortexSession::empty()) diff --git a/vortex-cuda/src/device_buffer.rs b/vortex-cuda/src/device_buffer.rs index 3257318cde4..e0f6477a9e3 100644 --- a/vortex-cuda/src/device_buffer.rs +++ b/vortex-cuda/src/device_buffer.rs @@ -1,8 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::any::Any; use std::cmp::min; use std::fmt::Debug; +use std::fmt::Formatter; +use std::hash::Hash; +use std::hash::Hasher; use std::ops::Range; use std::sync::Arc; @@ -11,6 +15,7 @@ use cudarc::driver::CudaView; use cudarc::driver::DevicePtr; use cudarc::driver::DeviceRepr; use cudarc::driver::sys; +use futures::executor::block_on; use futures::future::BoxFuture; use vortex::array::buffer::BufferHandle; use vortex::array::buffer::DeviceBuffer; @@ -174,7 +179,7 @@ impl CudaBufferExt for BufferHandle { } impl Debug for CudaDeviceBuffer { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("CudaDeviceBuffer") .field("allocation", &self.allocation) .field("device_ptr", &self.device_ptr) @@ -184,8 +189,8 @@ impl Debug for CudaDeviceBuffer { } } -impl std::hash::Hash for CudaDeviceBuffer { - fn hash(&self, state: &mut H) { +impl Hash for CudaDeviceBuffer { + fn hash(&self, state: &mut H) { self.device_ptr.hash(state); self.len.hash(state); self.offset.hash(state); @@ -224,7 +229,7 @@ impl DeviceBuffer for CudaDeviceBuffer { /// /// Returns an error if the CUDA memory copy operation fails. fn copy_to_host_sync(&self, alignment: Alignment) -> VortexResult { - futures::executor::block_on(self.copy_to_host(alignment)?) + block_on(self.copy_to_host(alignment)?) } /// Copies a device buffer to host memory asynchronously. @@ -322,7 +327,7 @@ impl DeviceBuffer for CudaDeviceBuffer { }) } - fn as_any(&self) -> &dyn std::any::Any { + fn as_any(&self) -> &dyn Any { self } diff --git a/vortex-cuda/src/dynamic_dispatch/mod.rs b/vortex-cuda/src/dynamic_dispatch/mod.rs index d6b25bc5147..cc52995b484 100644 --- a/vortex-cuda/src/dynamic_dispatch/mod.rs +++ b/vortex-cuda/src/dynamic_dispatch/mod.rs @@ -388,11 +388,11 @@ impl ScalarOp { } } - /// ALP floating-point decode. - pub fn alp(f: f32, e: f32) -> Self { + /// ALP floating-point decode (f32 or f64). + pub fn alp(f: f64, e: f64, output_ptype: PTypeTag) -> Self { Self { op_code: ScalarOp_ScalarOpCode_ALP, - output_ptype: PTypeTag_PTYPE_F32, + output_ptype, params: ScalarParams { alp: ScalarParams_AlpParams { f, @@ -436,7 +436,7 @@ impl MaterializedPlan { PType::U8 | PType::I8 => PType::U8, PType::U16 | PType::I16 => PType::U16, PType::U32 | PType::I32 | PType::F32 => PType::U32, - PType::U64 | PType::I64 => PType::U64, + PType::U64 | PType::I64 | PType::F64 => PType::U64, other => vortex_bail!("dynamic dispatch does not support PType {:?}", other), }; match_each_unsigned_integer_ptype!(unsigned_ptype, |T| { @@ -538,6 +538,7 @@ mod tests { use crate::CudaDeviceBuffer; use crate::CudaExecutionCtx; use crate::executor::CudaArrayExt; + use crate::executor::CudaDispatchMode; use crate::hybrid_dispatch::try_gpu_dispatch; use crate::session::CudaSession; @@ -559,7 +560,7 @@ mod tests { array: &vortex::array::ArrayRef, ctx: &mut CudaExecutionCtx, ) -> VortexResult { - match DispatchPlan::new(array)? { + match DispatchPlan::new(array, CudaDispatchMode::DynDispatchOnly)? { DispatchPlan::Fused(plan) => plan.materialize(ctx).await, _ => vortex_bail!("array encoding not fusable"), } @@ -707,7 +708,7 @@ mod tests { &[ ScalarOp::frame_of_ref(reference as u64, PTypeTag_PTYPE_U32), ScalarOp::zigzag(PTypeTag_PTYPE_U32), - ScalarOp::alp(alp_f, alp_e), + ScalarOp::alp(alp_f as f64, alp_e as f64, PTypeTag_PTYPE_F32), ], )], PTypeTag_PTYPE_U32, @@ -1100,7 +1101,7 @@ mod tests { // Mixed-width Dict (u8 codes, u32 values): both are Primitive, so // walk_mixed_width_child grabs the codes buffer directly as a LOAD // source. No pending subtrees → Fused. - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Fused(..)), "expected Fused for mixed-width Dict with primitive codes" @@ -1132,7 +1133,7 @@ mod tests { // Mixed-width Dict (u16 codes, u32 values): both are Primitive, so // walk_mixed_width_child grabs the codes buffer directly as a LOAD // source. No pending subtrees → Fused. - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Fused(..)), "expected Fused for mixed-width Dict with primitive codes" @@ -1164,7 +1165,7 @@ mod tests { // Ends (u64) are wider than values (u32), so the kernel would truncate // ends via load_element. The plan builder rejects this as Unfused. - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Unfused), "expected Unfused for RunEnd with wider ends" @@ -1746,17 +1747,228 @@ mod tests { Ok(()) } + // --------------------------------------------------------------- + // has_standalone_kernel classification tests + // --------------------------------------------------------------- + + #[crate::test] + fn test_has_standalone_kernel_true_cases() -> VortexResult<()> { + // BitPacked — leaf encoding, no children. + let bp = bitpacked_array_u32(6, 2048); + let bp_arr = bp.into_array(); + assert!(plan_builder::has_standalone_kernel(&bp_arr)); + + // Sequence — leaf encoding, no children. + use vortex::dtype::Nullability; + use vortex::encodings::sequence::Sequence; + let seq = Sequence::try_new_typed(0u32, 1u32, Nullability::NonNullable, 2048)?; + assert!(plan_builder::has_standalone_kernel(&seq.into_array())); + + // FoR(BitPacked) — FFOR fusion, single launch. + let for_bp = FoR::try_new(bp_arr.clone(), 100u32.into())?; + assert!(plan_builder::has_standalone_kernel(&for_bp.into_array())); + + // FoR(Slice(BitPacked)) — FFOR + slice fusion, single launch. + let sliced_bp = bp_arr.slice(100..1500)?; + let for_sliced_bp = FoR::try_new(sliced_bp, 100u32.into())?; + assert!(plan_builder::has_standalone_kernel( + &for_sliced_bp.into_array() + )); + + Ok(()) + } + + #[crate::test] + fn test_has_standalone_kernel_false_cases() -> VortexResult<()> { + // ALP(Primitive) — ALP always calls execute_cuda on its encoded child. + let encoded = + PrimitiveArray::new(Buffer::from((0i32..2048).collect::>()), NonNullable); + let alp = ALP::try_new(encoded.into_array(), Exponents { e: 2, f: 0 }, None)?; + assert!(!plan_builder::has_standalone_kernel(&alp.into_array())); + + // FoR(Primitive) — FoR standalone would recurse for non-BP child. + let prim = PrimitiveArray::new(Buffer::from(vec![1u32, 2, 3]), NonNullable); + let for_prim = FoR::try_new(prim.into_array(), 100u32.into())?; + assert!(!plan_builder::has_standalone_kernel(&for_prim.into_array())); + + // Dict and RunEnd always recurse into children. + let codes = PrimitiveArray::new(Buffer::from(vec![0u32, 1, 0, 1]), NonNullable); + let values = PrimitiveArray::new(Buffer::from(vec![100u32, 200]), NonNullable); + let dict = DictArray::try_new(codes.into_array(), values.into_array())?; + assert!(!plan_builder::has_standalone_kernel(&dict.into_array())); + + Ok(()) + } + + /// Every encoding `has_standalone_kernel` returns `true` for must have + /// a kernel registered in the CUDA session. + #[crate::test] + fn test_has_standalone_kernel_implies_registered_kernel() -> VortexResult<()> { + use vortex::dtype::Nullability; + use vortex::encodings::sequence::Sequence; + + let session = CudaSession::create_execution_ctx(&VortexSession::empty())?; + let cuda_session = session.cuda_session(); + + // Leaf encodings. + let bp = bitpacked_array_u32(6, 2048); + let bp_arr = bp.into_array(); + let seq = Sequence::try_new_typed(0u32, 1u32, Nullability::NonNullable, 2048)?; + let seq_arr = seq.into_array(); + + // FoR fusions. + let for_bp = FoR::try_new(bp_arr.clone(), 100u32.into())?; + let sliced_bp = bp_arr.slice(100..1500)?; + let for_sliced_bp = FoR::try_new(sliced_bp, 100u32.into())?; + + // With patches: some values exceed 2^4-1, creating overflow exceptions. + let values: Vec = (0..2048) + .map(|i| if i % 100 == 0 { 1000 } else { (i as u32) % 16 }) + .collect(); + let patched_bp = BitPacked::encode( + &PrimitiveArray::new(Buffer::from(values), NonNullable).into_array(), + 4, + &mut LEGACY_SESSION.create_execution_ctx(), + )?; + assert!(patched_bp.patches().is_some(), "expected patches"); + let patched_bp_arr = patched_bp.into_array(); + let for_patched_bp = FoR::try_new(patched_bp_arr.clone(), 100u32.into())?; + + for array in [ + &bp_arr, + &seq_arr, + &for_bp.into_array(), + &for_sliced_bp.into_array(), + &patched_bp_arr, + &for_patched_bp.into_array(), + ] { + assert!( + plan_builder::has_standalone_kernel(array), + "expected has_standalone_kernel=true for {:?}", + array.encoding_id() + ); + assert!( + cuda_session.kernel(&array.encoding_id()).is_some(), + "has_standalone_kernel=true but no kernel registered for {:?}", + array.encoding_id() + ); + } + + Ok(()) + } + #[crate::test] - fn test_f64_rejected() { - // F64 arrays should be rejected by the plan builder, not silently accepted. + fn test_f64_primitive_fuses() { + // Raw F64 primitives are now accepted — the kernel operates on uint64_t + // (same bit width), so LOAD correctly preserves the f64 bit pattern. let values: Vec = vec![1.0, 2.0, 3.0]; let primitive = PrimitiveArray::new(Buffer::from(values), NonNullable); - let plan = DispatchPlan::new(&primitive.into_array()) - .expect("DispatchPlan::new should not fail for f64"); + let plan = DispatchPlan::new(&primitive.into_array(), CudaDispatchMode::Auto) + .expect("DispatchPlan::new should not fail for f64 primitive"); assert!( - matches!(plan, DispatchPlan::Unfused), - "expected F64 to be classified as Unfused" + matches!(plan, DispatchPlan::Fused(_)), + "expected F64 primitive to be classified as Fused" + ); + } + + #[crate::test] + async fn test_alp_f64_for_bitpacked() -> VortexResult<()> { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + // ALP(FoR(BitPacked)) with f64: same structure as the f32 test. + let len = 3000; + let exponents = Exponents { e: 2, f: 0 }; + let floats: Vec = (0..len) + .map(|i| ::decode_single(10 + (i as i64 % 64), exponents)) + .collect(); + let float_prim = PrimitiveArray::new(Buffer::from(floats), NonNullable); + + let alp = alp_encode(float_prim.as_view(), Some(exponents), &mut ctx)?; + assert!(alp.patches().is_none()); + let for_arr = FoR::encode(alp.encoded().clone().execute::(&mut ctx)?)?; + let bp = BitPacked::encode( + for_arr.encoded(), + 6, + &mut LEGACY_SESSION.create_execution_ctx(), + )?; + + let tree = ALP::new( + FoR::try_new(bp.into_array(), for_arr.reference_scalar().clone())?.into_array(), + exponents, + None, ); + let array = tree.into_array(); + + // CPU decode as ground truth. + let cpu = array + .clone() + .execute::(&mut LEGACY_SESSION.create_execution_ctx())? + .into_array(); + + // GPU decode. + let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty())?; + let canonical = try_gpu_dispatch(&array, &mut cuda_ctx).await?; + let gpu = CanonicalCudaExt::into_host(canonical).await?.into_array(); + + vortex::array::assert_arrays_eq!(cpu, gpu); + + Ok(()) + } + + #[rstest] + #[case(4096, None)] + #[case(4096, Some(100..3000))] + #[crate::test] + async fn test_alp_f64_with_patches( + #[case] len: usize, + #[case] slice_range: Option>, + ) -> VortexResult<()> { + let mut values: Vec = (0..len).map(|i| (i as f64) * 1.1).collect(); + // Insert exception values that ALP can't encode. + values[0] = 99.9; + values[500] = std::f64::consts::PI; + values[1024] = std::f64::consts::E; + if len > 2048 { + values[2048] = std::f64::consts::LN_2; + } + if len > 3333 { + values[3333] = std::f64::consts::SQRT_2; + } + + let float_prim = PrimitiveArray::new(Buffer::from(values), NonNullable); + let encoded = alp_encode( + float_prim.as_view(), + None, + &mut LEGACY_SESSION.create_execution_ctx(), + )? + .into_array(); + + let (array, base_offset) = if let Some(ref range) = slice_range { + (encoded.slice(range.clone())?, range.start) + } else { + (encoded, 0) + }; + + // Decode on CPU as ground truth (accounts for ALP precision loss + patches). + let cpu_decoded = array + .clone() + .execute::(&mut LEGACY_SESSION.create_execution_ctx())?; + let expected: Vec = cpu_decoded.as_slice::().to_vec(); + + let mut cuda_ctx = CudaSession::create_execution_ctx(&VortexSession::empty())?; + let canonical = try_gpu_dispatch(&array, &mut cuda_ctx).await?; + let result = CanonicalCudaExt::into_host(canonical).await?; + let result_prim = result.as_primitive(); + let actual: Vec = result_prim.as_slice::().to_vec(); + for (i, (&a, &e)) in actual.iter().zip(expected.iter()).enumerate() { + assert!( + a.to_bits() == e.to_bits(), + "mismatch at index {i} (original index {}): gpu={a} cpu={e} (bits: {:#018x} vs {:#018x})", + i + base_offset, + a.to_bits(), + e.to_bits(), + ); + } + Ok(()) } #[crate::test] @@ -1775,7 +1987,7 @@ mod tests { // Ends (u32) are wider than values (u16), so the kernel would truncate // ends via load_element. The plan builder rejects this as Unfused. - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Unfused), "expected Unfused for RunEnd with wider ends" @@ -1824,7 +2036,7 @@ mod tests { let dict = DictArray::try_new(codes_bp.into_array(), values_prim.into_array())?; let array = dict.into_array(); - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Fused(..)), "expected Fused for mixed-width Dict with BitPacked codes" @@ -1868,7 +2080,7 @@ mod tests { let dict = DictArray::try_new(codes_bp.into_array(), values_prim.into_array())?; let array = dict.into_array(); - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Fused(..)), "expected Fused for mixed-width Dict with BitPacked codes" @@ -1912,7 +2124,7 @@ mod tests { let dict = DictArray::try_new(codes_for.into_array(), values_prim.into_array())?; let array = dict.into_array(); - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Fused(..)), "expected Fused for mixed-width Dict with FoR(BitPacked) codes" @@ -1969,7 +2181,7 @@ mod tests { let re = RunEnd::new(ends_bp.into_array(), values_prim.into_array(), &mut ctx); let array = re.into_array(); - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Fused(..)), "expected Fused for mixed-width RunEnd with BitPacked ends" @@ -2015,7 +2227,7 @@ mod tests { let re = RunEnd::new(ends_for.into_array(), values_prim.into_array(), &mut ctx); let array = re.into_array(); - let plan = DispatchPlan::new(&array)?; + let plan = DispatchPlan::new(&array, CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Fused(..)), "expected Fused for mixed-width RunEnd with FoR(BitPacked) ends" @@ -2207,10 +2419,10 @@ mod tests { // Verify the plan actually fuses (not just a LOAD). assert!( matches!( - DispatchPlan::new(&for_arr.clone().into_array())?, - DispatchPlan::Fused(_) + DispatchPlan::new(&for_arr.clone().into_array(), CudaDispatchMode::Auto)?, + DispatchPlan::Standalone | DispatchPlan::Fused(_) ), - "FoR(BitPacked) with nullable validity should produce a Fused plan" + "FoR(BitPacked) with nullable validity should be fusable" ); let gpu = try_gpu_dispatch(&for_arr.into_array(), &mut cuda_ctx) @@ -2269,7 +2481,7 @@ mod tests { let values = PrimitiveArray::new(buffer![10u32, 20, 30], NonNullable); let dict = DictArray::try_new(codes.into_array(), values.into_array())?; - let plan = DispatchPlan::new(&dict.into_array())?; + let plan = DispatchPlan::new(&dict.into_array(), CudaDispatchMode::Auto)?; assert!( matches!(plan, DispatchPlan::Unfused), "Dict with nullable codes should fall back to Unfused" diff --git a/vortex-cuda/src/dynamic_dispatch/plan_builder.rs b/vortex-cuda/src/dynamic_dispatch/plan_builder.rs index 0aecfd120a0..e887f1ba53f 100644 --- a/vortex-cuda/src/dynamic_dispatch/plan_builder.rs +++ b/vortex-cuda/src/dynamic_dispatch/plan_builder.rs @@ -40,6 +40,8 @@ use vortex::error::vortex_err; use super::CudaDispatchPlan; use super::MaterializedStage; use super::PTypeTag; +use super::PTypeTag_PTYPE_F32; +use super::PTypeTag_PTYPE_F64; use super::SMEM_TILE_SIZE; use super::ScalarOp; use super::SourceOp; @@ -47,6 +49,7 @@ use super::ptype_to_tag; use super::tag_to_ptype; use crate::CudaBufferExt; use crate::CudaExecutionCtx; +use crate::executor::CudaDispatchMode; use crate::kernel::load_patches_to_gpu; /// A plan whose source buffers have been copied to the device, ready for kernel launch. @@ -63,16 +66,15 @@ pub struct MaterializedPlan { /// Checks whether the encoding of an array can be fused into a dynamic-dispatch plan. fn is_dyn_dispatch_compatible(array: &ArrayRef) -> bool { - // The dynamic dispatch kernel only supports F32 floats (via ALP). - // F16 and F64 have no reinterpret path in the kernel. - if matches!(PType::try_from(array.dtype()), Ok(PType::F16 | PType::F64)) { + // F16 has no reinterpret path in the kernel. + if matches!(PType::try_from(array.dtype()), Ok(PType::F16)) { return false; } let id = array.encoding_id(); if id == ALP.id() { let arr = array.as_::(); - return arr.dtype().as_ptype() == PType::F32; + return matches!(arr.dtype().as_ptype(), PType::F32 | PType::F64); } if id == BitPacked.id() { return true; @@ -121,6 +123,33 @@ fn is_dyn_dispatch_compatible(array: &ArrayRef) -> bool { || id == Sequence.id() } +/// Returns `true` if a registered standalone kernel can decode the entire +/// `array` tree in a single launch without recursing into `execute_cuda` +/// for child encodings. +pub fn has_standalone_kernel(array: &ArrayRef) -> bool { + let id = array.encoding_id(); + + // Leaf encodings: no children to recurse into. + if id == BitPacked.id() || id == Sequence.id() { + return true; + } + + // FoR fuses with BitPacked (FFOR) and Slice(BitPacked) in one launch. + if id == FoR.id() { + let for_arr = array.as_::(); + let child = for_arr.encoded(); + if child.encoding_id() == BitPacked.id() { + return true; + } + if let Some(slice) = child.as_opt::() { + return slice.child().encoding_id() == BitPacked.id(); + } + return false; + } + + false +} + /// An unmaterialized stage: a source op, scalar ops, and optional source buffer reference. /// /// Patches are tied to their owning ops, mirroring the CUDA side where @@ -160,6 +189,9 @@ type OutputLen = u32; /// Constructed by [`DispatchPlan::new`], which inspects the encoding tree /// and determines whether it can be fully fused, partially fused, or not fused at all. pub enum DispatchPlan { + /// A registered standalone kernel can decode the entire tree in a single + /// launch without recursing into child encodings. + Standalone, /// Entire encoding tree is fusable into a single kernel launch. Fused(FusedPlan), /// Some subtrees need separate execution before the fused plan can run. @@ -222,12 +254,21 @@ impl DispatchPlan { /// /// # Limitations /// - /// - Validity is propagated from the root array to the output. Nullable - /// arrays are supported, but Dict with nullable codes and RunEnd with - /// nullable ends are rejected to guard against out-of-bounds access. - /// - `BitPackedArray` and `ALPArray` with patches are supported. - /// - Only f32 ALP is supported (kernel stores multipliers as `float`). - pub fn new(array: &ArrayRef) -> VortexResult { + /// - **F16 primitives** are not supported (no reinterpret path in the kernel). + /// - **ALP** is supported for f32 and f64 only (including patches). + /// - **BitPacked** with patches is supported. + /// - **Dict** with nullable codes is rejected (garbage at null positions + /// could OOB the DICT gather). Dict with codes wider than values is + /// also rejected (load would truncate code indices). + /// - **RunEnd** with nullable ends is rejected (garbage values break the + /// binary search). RunEnd with ends wider than values is also rejected. + /// - Validity is propagated from the root array to the output. + /// - Unrecognized encodings fall back to `Unfused`. + pub fn new(array: &ArrayRef, mode: CudaDispatchMode) -> VortexResult { + if mode == CudaDispatchMode::Auto && has_standalone_kernel(array) { + return Ok(Self::Standalone); + } + if PType::try_from(array.dtype()).is_err() || !is_dyn_dispatch_compatible(array) { return Ok(Self::Unfused); } @@ -275,9 +316,6 @@ impl FusedPlan { array.dtype() ) })?; - if output_ptype_rust == PType::F64 { - vortex_bail!("dynamic dispatch does not support f64 output"); - } let output_elem_bytes = output_ptype_rust.byte_width() as u32; let output_ptype = ptype_to_tag(output_ptype_rust); let validity = array.validity()?; @@ -587,13 +625,35 @@ impl FusedPlan { exponents: Exponents, pending_subtrees: &mut Vec, ) -> VortexResult { - let alp_f = ::F10[exponents.f as usize]; - let alp_e = ::IF10[exponents.e as usize]; + let encoded_ptype = PType::try_from(encoded.dtype()).map_err(|_| { + vortex_err!( + "ALP encoded child must have primitive dtype, got {:?}", + encoded.dtype() + ) + })?; + // ALP encodes f32 as i32 and f64 as i64. Select the correct + // exponent tables and output PType based on the encoded integer width. + let (alp_f, alp_e, output_ptype) = match encoded_ptype { + PType::I32 => ( + ::F10[exponents.f as usize] as f64, + ::IF10[exponents.e as usize] as f64, + PTypeTag_PTYPE_F32, + ), + PType::I64 => ( + ::F10[exponents.f as usize], + ::IF10[exponents.e as usize], + PTypeTag_PTYPE_F64, + ), + other => vortex_bail!( + "ALP encoded ptype must be I32 (f32) or I64 (f64), got {:?}", + other + ), + }; let mut pipeline = self.walk(encoded, pending_subtrees)?; pipeline .scalar_ops - .push((ScalarOp::alp(alp_f, alp_e), patches)); + .push((ScalarOp::alp(alp_f, alp_e, output_ptype), patches)); Ok(pipeline) } @@ -619,8 +679,7 @@ impl FusedPlan { /// Called from [`walk`] when [`is_dyn_dispatch_compatible`] rejects a child. /// Cases that require a separate kernel dispatch: /// - /// - **F16 / F64 primitives** — no reinterpret path in the kernel. - /// - **ALP with non-F32 dtype** — only F32 ALP is supported. + /// - **F16 primitives** — no reinterpret path in the kernel. /// - **Dict with nullable codes** — garbage at null positions could OOB /// the DICT gather in shared memory. /// - **Dict with codes wider than values** — `load_element()` would diff --git a/vortex-cuda/src/hybrid_dispatch/mod.rs b/vortex-cuda/src/hybrid_dispatch/mod.rs index 59ec18aa938..eb0727e992f 100644 --- a/vortex-cuda/src/hybrid_dispatch/mod.rs +++ b/vortex-cuda/src/hybrid_dispatch/mod.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors -//! Hybrid dispatch: fuses dynamic-dispatch plans with single-kernel fallbacks. +//! Hybrid dispatch: routes arrays to standalone kernels or fused dynamic-dispatch plans. //! //! When an array is executed on the GPU, we fuse as much of its encoding //! tree as possible into a single kernel launch via [`DispatchPlan`]. @@ -18,10 +18,15 @@ //! //! Strategies tried in order: //! -//! 1. Fully fused — no unfusable nodes, entire tree compiles into one +//! 1. Standalone — a registered kernel covers the entire tree in a single +//! launch without recursing into child encodings. Preferred when applicable +//! because the kernel is hand-tuned for that exact scenario. Detected by +//! `has_standalone_kernel`. +//! +//! 2. Fully fused — no unfusable nodes, entire tree compiles into one //! [`DispatchPlan`] → `MaterializedPlan` → kernel launch. //! -//! 2. Partial fusion — `pending_subtrees` from the `PartiallyFused` +//! 3. Partial fusion — `pending_subtrees` from the `PartiallyFused` //! variant are executed first (sequentially, same stream), their device buffers //! become `LOAD` ops in a fused plan via `FusedPlan::materialize_with_subtrees`. //! Each subtree re-enters [`try_gpu_dispatch`] and may itself fuse. @@ -30,10 +35,10 @@ //! happens in-kernel via `load_element()` in the LOAD source op — no //! separate widen pass is needed. //! -//! 3. Fallback — root is not fusable. Delegate to its registered +//! 4. Fallback — root is not fusable. Delegate to its registered //! `CudaExecute` kernel; its children re-enter [`try_gpu_dispatch`]. //! -//! All three compose recursively to arbitrary depth. +//! All four compose recursively. //! //! Zone-map pruning is handled by ZonedReader before chunks reach the plan //! builder. Filtering within a chunk is done after decompression, not as push-down. @@ -55,12 +60,14 @@ use crate::dynamic_dispatch::plan_builder::DispatchPlan; use crate::executor::CudaArrayExt; use crate::executor::CudaExecutionCtx; -/// Try to execute `array` on the GPU, attempting three strategies in order: +/// Try to execute `array` on the GPU, attempting four strategies in order: /// -/// 1. Fully fused — [`DispatchPlan::new`] + `FusedPlan::materialize`. -/// 2. Partially fused — pending subtrees executed first, then +/// 1. Standalone — a registered kernel covers the entire tree without +/// recursing into child encodings (e.g. FFOR, ALP(Primitive)). +/// 2. Fully fused — [`DispatchPlan::new`] + `FusedPlan::materialize`. +/// 3. Partially fused — pending subtrees executed first, then /// `FusedPlan::materialize_with_subtrees`. -/// 3. Fallback — root encoding's `CudaExecute` kernel; children +/// 4. Fallback — root encoding's `CudaExecute` kernel; children /// re-enter this function recursively. /// /// Returns `Ok(Canonical)` on success. Returns `Err` when the array @@ -85,7 +92,17 @@ pub async fn try_gpu_dispatch( .await; } - match DispatchPlan::new(array)? { + match DispatchPlan::new(array, ctx.dispatch_mode())? { + DispatchPlan::Standalone => { + trace!(encoding = %array.encoding_id(), "standalone dispatch"); + ctx.cuda_session() + .kernel(&array.encoding_id()) + .ok_or_else(|| { + vortex_err!("No CUDA kernel for encoding {:?}", array.encoding_id()) + })? + .execute(array.clone(), ctx) + .await + } DispatchPlan::Fused(plan) => { let materialized = plan.materialize(ctx).await?; let num_stages = materialized.dispatch_plan.num_stages(); diff --git a/vortex-cuda/src/kernel/encodings/zstd.rs b/vortex-cuda/src/kernel/encodings/zstd.rs index fe46b308e04..0364950d148 100644 --- a/vortex-cuda/src/kernel/encodings/zstd.rs +++ b/vortex-cuda/src/kernel/encodings/zstd.rs @@ -29,6 +29,7 @@ use vortex::encodings::zstd::Zstd; use vortex::encodings::zstd::ZstdArray; use vortex::encodings::zstd::ZstdDataParts; use vortex::encodings::zstd::ZstdMetadata; +use vortex::encodings::zstd::reconstruct_views; use vortex::error::VortexExpect; use vortex::error::VortexResult; use vortex::error::vortex_bail; @@ -330,8 +331,7 @@ async fn decode_zstd(array: ZstdArray, ctx: &mut CudaExecutionCtx) -> VortexResu .indices() { AllOr::All => { - let (buffers, all_views) = - vortex::encodings::zstd::reconstruct_views(&host_buffer, MAX_BUFFER_LEN); + let (buffers, all_views) = reconstruct_views(&host_buffer, MAX_BUFFER_LEN); let sliced_views = all_views.slice(slice_value_idx_start..slice_value_idx_stop); Ok(Canonical::VarBinView(unsafe { diff --git a/vortex-cuda/src/kernel/encodings/zstd_buffers.rs b/vortex-cuda/src/kernel/encodings/zstd_buffers.rs index c31ab65fadb..8a67a338ca5 100644 --- a/vortex-cuda/src/kernel/encodings/zstd_buffers.rs +++ b/vortex-cuda/src/kernel/encodings/zstd_buffers.rs @@ -18,6 +18,7 @@ use vortex::buffer::Alignment; use vortex::buffer::Buffer; use vortex::encodings::zstd::ZstdBuffers; use vortex::encodings::zstd::ZstdBuffersArray; +use vortex::encodings::zstd::ZstdBuffersDecodePlan; use vortex::error::VortexResult; use vortex::error::vortex_err; use vortex_nvcomp::sys; @@ -175,7 +176,7 @@ async fn move_frames_to_device( // This performs D2H to retrieve the lengths and status arrays. async fn validate_decompress_results( - plan: &vortex::encodings::zstd::ZstdBuffersDecodePlan, + plan: &ZstdBuffersDecodePlan, device_actual_sizes: CudaSlice, device_statuses: CudaSlice, ) -> VortexResult<()> { diff --git a/vortex-cuda/src/kernel/patches/mod.rs b/vortex-cuda/src/kernel/patches/mod.rs index 6075b664f72..90ec3fc9c99 100644 --- a/vortex-cuda/src/kernel/patches/mod.rs +++ b/vortex-cuda/src/kernel/patches/mod.rs @@ -16,6 +16,7 @@ use vortex::array::arrays::primitive::PrimitiveDataParts; use vortex::array::patches::Patches; use vortex::array::validity::Validity; use vortex::dtype::NativePType; +use vortex::dtype::PType; use vortex::error::VortexResult; use vortex::error::vortex_bail; use vortex::error::vortex_ensure; @@ -51,12 +52,12 @@ impl GPUPatches { } /// Convert a [`PType`] to the corresponding [`ChunkOffsetType`] for GPU patches. -fn ptype_to_chunk_offset_type(ptype: vortex::dtype::PType) -> VortexResult { +fn ptype_to_chunk_offset_type(ptype: PType) -> VortexResult { match ptype { - vortex::dtype::PType::U8 => Ok(ChunkOffsetType_CO_U8), - vortex::dtype::PType::U16 => Ok(ChunkOffsetType_CO_U16), - vortex::dtype::PType::U32 => Ok(ChunkOffsetType_CO_U32), - vortex::dtype::PType::U64 => Ok(ChunkOffsetType_CO_U64), + PType::U8 => Ok(ChunkOffsetType_CO_U8), + PType::U16 => Ok(ChunkOffsetType_CO_U16), + PType::U32 => Ok(ChunkOffsetType_CO_U32), + PType::U64 => Ok(ChunkOffsetType_CO_U64), _ => vortex_bail!("Invalid PType for chunk_offsets: {:?}", ptype), } } diff --git a/vortex-cuda/src/pinned.rs b/vortex-cuda/src/pinned.rs index 80c57ee99b6..cd97db63164 100644 --- a/vortex-cuda/src/pinned.rs +++ b/vortex-cuda/src/pinned.rs @@ -2,6 +2,8 @@ // SPDX-FileCopyrightText: Copyright the Vortex contributors use std::sync::Arc; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering; use cudarc::driver::CudaContext; use cudarc::driver::CudaEvent; @@ -105,10 +107,10 @@ pub struct PinnedByteBufferPool { max_keep_per_size: usize, buckets: Mutex>>, inflight: Mutex>, - hits: std::sync::atomic::AtomicU64, - misses: std::sync::atomic::AtomicU64, - allocs: std::sync::atomic::AtomicU64, - puts: std::sync::atomic::AtomicU64, + hits: AtomicU64, + misses: AtomicU64, + allocs: AtomicU64, + puts: AtomicU64, } struct InflightPinnedBuffer { @@ -129,10 +131,10 @@ impl PinnedByteBufferPool { max_keep_per_size: max_keep_per_size.max(1), buckets: Mutex::new(HashMap::new()), inflight: Mutex::new(Vec::new()), - hits: std::sync::atomic::AtomicU64::new(0), - misses: std::sync::atomic::AtomicU64::new(0), - allocs: std::sync::atomic::AtomicU64::new(0), - puts: std::sync::atomic::AtomicU64::new(0), + hits: AtomicU64::new(0), + misses: AtomicU64::new(0), + allocs: AtomicU64::new(0), + puts: AtomicU64::new(0), } } @@ -169,10 +171,10 @@ impl PinnedByteBufferPool { /// Snapshot pool reuse statistics. pub fn stats(&self) -> PinnedPoolStats { PinnedPoolStats { - hits: self.hits.load(std::sync::atomic::Ordering::Relaxed), - misses: self.misses.load(std::sync::atomic::Ordering::Relaxed), - allocs: self.allocs.load(std::sync::atomic::Ordering::Relaxed), - puts: self.puts.load(std::sync::atomic::Ordering::Relaxed), + hits: self.hits.load(Ordering::Relaxed), + misses: self.misses.load(Ordering::Relaxed), + allocs: self.allocs.load(Ordering::Relaxed), + puts: self.puts.load(Ordering::Relaxed), } } @@ -211,16 +213,14 @@ impl PinnedByteBufferPool { if let Some(bucket) = buckets.get_mut(&key_len) && let Some(buf) = bucket.pop() { - self.hits.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + self.hits.fetch_add(1, Ordering::Relaxed); let mut buf = buf; buf.set_logical_len(len); return Ok(buf); } } - self.misses - .fetch_add(1, std::sync::atomic::Ordering::Relaxed); - self.allocs - .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + self.misses.fetch_add(1, Ordering::Relaxed); + self.allocs.fetch_add(1, Ordering::Relaxed); unsafe { PinnedByteBuffer::uninit_with_capacity(&self.ctx, key_len, len) } } @@ -238,7 +238,7 @@ impl PinnedByteBufferPool { }; // If the pool is full, the buffer (cuMemFreeHost) is dropped outside the lock. drop(overflow); - self.puts.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + self.puts.fetch_add(1, Ordering::Relaxed); } fn try_get_inner(&self, len: usize) -> VortexResult> { @@ -248,7 +248,7 @@ impl PinnedByteBufferPool { if let Some(bucket) = buckets.get_mut(&key_len) && let Some(mut buf) = bucket.pop() { - self.hits.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + self.hits.fetch_add(1, Ordering::Relaxed); buf.set_logical_len(len); Ok(Some(buf)) } else { diff --git a/vortex-cuda/src/session.rs b/vortex-cuda/src/session.rs index cbb2ff79726..4ef1736021c 100644 --- a/vortex-cuda/src/session.rs +++ b/vortex-cuda/src/session.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::any::Any; use std::fmt::Debug; use std::sync::Arc; @@ -10,6 +11,7 @@ use vortex::array::VortexSessionExecute; use vortex::error::VortexResult; use vortex::session::Ref; use vortex::session::SessionExt; +use vortex::session::SessionVar; use vortex::utils::aliases::dash_map::DashMap; use crate::ExportDeviceArray; @@ -147,6 +149,16 @@ impl Default for CudaSession { } } +impl SessionVar for CudaSession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Extension trait for accessing the CUDA session from a Vortex session. pub trait CudaSessionExt: SessionExt { /// Returns the CUDA session. diff --git a/vortex-datafusion/src/v2/source.rs b/vortex-datafusion/src/v2/source.rs index 80a00a7efbe..8efebb04267 100644 --- a/vortex-datafusion/src/v2/source.rs +++ b/vortex-datafusion/src/v2/source.rs @@ -500,10 +500,10 @@ impl DataSource for VortexDataSource { fn partition_statistics(&self, _partition: Option) -> DFResult { // FIXME(ngates): this should be adjusted based on filters. See DuckDB for heuristics, // and in the future, store the selectivity stats in the session. - let num_rows = estimate_to_df_precision(&self.data_source.row_count()); + let num_rows = estimate_to_df_precision(self.data_source.row_count().as_ref()); // FIXME(ngates): byte size should be adjusted for the initial projection... - let total_byte_size = estimate_to_df_precision(&self.data_source.byte_size()); + let total_byte_size = estimate_to_df_precision(self.data_source.byte_size().as_ref()); // Column statistics must match the output schema (leftover_schema), which may differ // from the initial schema after try_swapping_with_projection adds computed columns. @@ -654,7 +654,7 @@ impl DataSource for VortexDataSource { /// [`DataFusionPrecision`]. /// /// [`DataFusionPrecision`]: datafusion_common::stats::Precision -fn estimate_to_df_precision(est: &Option>) -> DFPrecision { +fn estimate_to_df_precision(est: Option<&Precision>) -> DFPrecision { match est { Some(Precision::Exact(v)) => DFPrecision::Exact(usize::try_from(*v).unwrap_or(usize::MAX)), Some(Precision::Inexact(v)) => { diff --git a/vortex-file/src/file.rs b/vortex-file/src/file.rs index 7257676b05c..f321d774197 100644 --- a/vortex-file/src/file.rs +++ b/vortex-file/src/file.rs @@ -12,7 +12,9 @@ use std::sync::Arc; use itertools::Itertools; use vortex_array::ArrayRef; use vortex_array::Columnar; +use vortex_array::IntoArray; use vortex_array::VortexSessionExecute; +use vortex_array::arrays::ConstantArray; use vortex_array::dtype::DType; use vortex_array::dtype::Field; use vortex_array::dtype::FieldMask; @@ -20,6 +22,7 @@ use vortex_array::dtype::FieldPath; use vortex_array::dtype::FieldPathSet; use vortex_array::expr::Expression; use vortex_array::expr::pruning::checked_pruning_expr; +use vortex_array::scalar_fn::internal::row_count::substitute_row_count; use vortex_error::VortexResult; use vortex_layout::LayoutReader; use vortex_layout::scan::layout::LayoutReaderDataSource; @@ -117,7 +120,11 @@ impl VortexFile { )) } - /// Returns true if the expression will never match any rows in the file. + /// Returns `true` if file-level statistics prove the expression cannot + /// match any rows in this file. + /// + /// Row-count-aware pruning predicates are evaluated with the file's total + /// row count as their scope. pub fn can_prune(&self, filter: &Expression) -> VortexResult { let Some((stats, fields)) = self .footer @@ -162,16 +169,18 @@ impl VortexFile { return Ok(false); }; + // Apply the predicate, then substitute any row_count placeholders in the resulting array + // tree with a ConstantArray carrying the file-level row count. + let applied = file_stats.apply(&predicate)?; + let row_count_replacement = + ConstantArray::new(self.footer.row_count(), applied.len()).into_array(); + let applied = substitute_row_count(applied, &row_count_replacement)?; + let mut ctx = self.session.create_execution_ctx(); - Ok( - match file_stats - .apply(&predicate)? - .execute::(&mut ctx)? - { - Columnar::Constant(s) => s.scalar().as_bool().value() == Some(true), - Columnar::Canonical(_) => false, - }, - ) + Ok(match applied.execute::(&mut ctx)? { + Columnar::Constant(s) => s.scalar().as_bool().value() == Some(true), + Columnar::Canonical(_) => false, + }) } pub fn splits(&self) -> VortexResult>> { diff --git a/vortex-file/src/multi/session.rs b/vortex-file/src/multi/session.rs index d7705006d37..7023d3cd020 100644 --- a/vortex-file/src/multi/session.rs +++ b/vortex-file/src/multi/session.rs @@ -3,10 +3,12 @@ //! Session extension for multi-file scanning, providing a shared footer cache. +use std::any::Any; use std::fmt; use std::fmt::Debug; use vortex_session::SessionExt; +use vortex_session::SessionVar; use crate::footer::Footer; @@ -61,6 +63,16 @@ impl MultiFileSession { } } +impl SessionVar for MultiFileSession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Extension trait for accessing the [`MultiFileSession`] from a session. pub(super) trait MultiFileSessionExt: SessionExt { /// Returns a reference to the [`MultiFileSession`] state. diff --git a/vortex-file/src/v2/file_stats_reader.rs b/vortex-file/src/v2/file_stats_reader.rs index 5634ec09bd4..f197fea32b6 100644 --- a/vortex-file/src/v2/file_stats_reader.rs +++ b/vortex-file/src/v2/file_stats_reader.rs @@ -15,6 +15,7 @@ use vortex_array::Canonical; use vortex_array::IntoArray; use vortex_array::MaskFuture; use vortex_array::VortexSessionExecute; +use vortex_array::arrays::ConstantArray; use vortex_array::arrays::NullArray; use vortex_array::dtype::DType; use vortex_array::dtype::FieldMask; @@ -26,6 +27,7 @@ use vortex_array::expr::lit; use vortex_array::expr::stats::Stat; use vortex_array::scalar::Scalar; use vortex_array::scalar_fn::fns::literal::Literal; +use vortex_array::scalar_fn::internal::row_count::substitute_row_count; use vortex_error::VortexResult; use vortex_layout::ArrayFuture; use vortex_layout::LayoutReader; @@ -75,18 +77,19 @@ impl FileStatsLayoutReader { } } - /// Evaluates whether the file can be fully pruned for the given expression. + /// Evaluates whether file-level statistics prove `expr` cannot match. /// - /// Returns `true` if file-level stats prove no rows can match, `false` otherwise. + /// Row-count placeholders are resolved against the full file row count, + /// independent of the requested row range. fn evaluate_file_stats(&self, expr: &Expression) -> VortexResult { let Some(pruning_expr) = expr.stat_falsification(self) else { // If there is no pruning expression, we can't prune. return Ok(false); }; - // Given how we implemented the StatsCatalog, we know the expression must be all literals. - // We can therefore optimize with a null scope since there are no field references that - // need to be resolved. + // Given how we implemented the StatsCatalog, we know the expression must be all literals + // or row_count placeholders. We can therefore optimize with a null scope since there are + // no field references that need to be resolved. let simplified = pruning_expr.optimize_recursive(&DType::Null)?; if let Some(result) = simplified.as_opt::() { // Can prune if the result is non-nullable and true @@ -94,8 +97,12 @@ impl FileStatsLayoutReader { } // Sometimes expressions don't implement constant folding to literals... In this case, - // we just execute the expression over a null array. + // we apply the expression over a null array and substitute any row_count placeholders + // in the resulting array tree with the file's row count. let pruning = NullArray::new(1).into_array().apply(&pruning_expr)?; + let row_count_replacement = + ConstantArray::new(self.child.row_count(), pruning.len()).into_array(); + let pruning = substitute_row_count(pruning, &row_count_replacement)?; let mut ctx = self.session.create_execution_ctx(); let result = pruning @@ -126,8 +133,6 @@ impl StatsCatalog for FileStatsLayoutReader { let stat_value = field_stats.get(stat)?.as_exact()?; let field_dtype = self.struct_fields.field_by_index(field_idx)?; - // Use the stat's own dtype rather than the field dtype. For example, - // NullCount is always u64 regardless of the column type. let stat_dtype = stat.dtype(&field_dtype)?; let stat_scalar = Scalar::try_new(stat_dtype, Some(stat_value)).ok()?; @@ -220,6 +225,7 @@ mod tests { use vortex_array::dtype::PType; use vortex_array::expr::get_item; use vortex_array::expr::gt; + use vortex_array::expr::is_not_null; use vortex_array::expr::is_null; use vortex_array::expr::lit; use vortex_array::expr::root; @@ -267,6 +273,18 @@ mod tests { ) } + fn test_file_null_count_stats(null_count: u64) -> FileStatistics { + let mut stats = StatsSet::default(); + stats.set( + Stat::NullCount, + Precision::exact(ScalarValue::from(null_count)), + ); + FileStatistics::new( + Arc::from([stats]), + Arc::from([DType::Primitive(PType::I32, Nullability::Nullable)]), + ) + } + #[test] fn pruning_when_filter_out_of_range() -> VortexResult<()> { block_on(|handle| async { @@ -400,4 +418,47 @@ mod tests { Ok(()) }) } + + #[test] + fn pruning_is_not_null_when_file_is_all_null() -> VortexResult<()> { + block_on(|handle| async { + let session = SESSION.clone().with_handle(handle); + let ctx = ArrayContext::empty(); + let segments = Arc::new(TestSegments::default()); + let (ptr, eof) = SequenceId::root().split(); + let struct_array = StructArray::from_fields( + [( + "col", + PrimitiveArray::from_option_iter([None::, None, None, None, None]) + .into_array(), + )] + .as_slice(), + )?; + let strategy = TableStrategy::new( + Arc::new(FlatLayoutStrategy::default()), + Arc::new(FlatLayoutStrategy::default()), + ); + let layout = strategy + .write_stream( + ctx, + Arc::clone(&segments) as Arc, + struct_array.into_array().to_array_stream().sequenced(ptr), + eof, + &session, + ) + .await?; + + let child = layout.new_reader("".into(), segments, &SESSION)?; + + let reader = + FileStatsLayoutReader::new(child, test_file_null_count_stats(5), SESSION.clone()); + + let expr = is_not_null(get_item("col", root())); + let mask = Mask::new_true(5); + let result = reader.pruning_evaluation(&(0..5), &expr, mask)?.await?; + assert_eq!(result, Mask::new_false(5)); + + Ok(()) + }) + } } diff --git a/vortex-io/public-api.lock b/vortex-io/public-api.lock index d611f71f785..30bf0f180e8 100644 --- a/vortex-io/public-api.lock +++ b/vortex-io/public-api.lock @@ -488,6 +488,12 @@ impl core::fmt::Debug for vortex_io::session::RuntimeSession pub fn vortex_io::session::RuntimeSession::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_io::session::RuntimeSession + +pub fn vortex_io::session::RuntimeSession::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_io::session::RuntimeSession::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub trait vortex_io::session::RuntimeSessionExt: vortex_session::SessionExt pub fn vortex_io::session::RuntimeSessionExt::handle(&self) -> vortex_io::runtime::Handle diff --git a/vortex-io/src/session.rs b/vortex-io/src/session.rs index 38500d248a0..42975ca70de 100644 --- a/vortex-io/src/session.rs +++ b/vortex-io/src/session.rs @@ -1,10 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::any::Any; use std::fmt::Debug; use vortex_error::VortexExpect; use vortex_session::SessionExt; +use vortex_session::SessionVar; use crate::runtime::Handle; @@ -13,6 +15,16 @@ pub struct RuntimeSession { handle: Option, } +impl SessionVar for RuntimeSession { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + impl Default for RuntimeSession { fn default() -> Self { Self { diff --git a/vortex-layout/Cargo.toml b/vortex-layout/Cargo.toml index 30a0953444a..61b1253ef43 100644 --- a/vortex-layout/Cargo.toml +++ b/vortex-layout/Cargo.toml @@ -47,6 +47,7 @@ vortex-flatbuffers = { workspace = true, features = ["layout"] } vortex-io = { workspace = true } vortex-mask = { workspace = true } vortex-metrics = { workspace = true } +vortex-runend = { workspace = true } vortex-scan = { workspace = true } vortex-sequence = { workspace = true } vortex-session = { workspace = true } diff --git a/vortex-layout/public-api.lock b/vortex-layout/public-api.lock index 6b029d9c50d..32fe19f9729 100644 --- a/vortex-layout/public-api.lock +++ b/vortex-layout/public-api.lock @@ -792,37 +792,17 @@ pub fn vortex_layout::layouts::zoned::writer::ZonedStrategy::write_stream<'life0 pub mod vortex_layout::layouts::zoned::zone_map -pub struct vortex_layout::layouts::zoned::zone_map::StatsAccumulator - -impl vortex_layout::layouts::zoned::zone_map::StatsAccumulator - -pub fn vortex_layout::layouts::zoned::zone_map::StatsAccumulator::as_stats_table(&mut self) -> vortex_error::VortexResult> - -pub fn vortex_layout::layouts::zoned::zone_map::StatsAccumulator::new(dtype: &vortex_array::dtype::DType, stats: &[vortex_array::expr::stats::Stat], max_variable_length_statistics_size: usize) -> Self - -pub fn vortex_layout::layouts::zoned::zone_map::StatsAccumulator::push_chunk(&mut self, array: &vortex_array::array::erased::ArrayRef, ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult<()> - -pub fn vortex_layout::layouts::zoned::zone_map::StatsAccumulator::push_chunk_without_compute(&mut self, array: &vortex_array::array::erased::ArrayRef) -> vortex_error::VortexResult<()> - pub struct vortex_layout::layouts::zoned::zone_map::ZoneMap impl vortex_layout::layouts::zoned::zone_map::ZoneMap -pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::array(&self) -> &vortex_array::arrays::struct_::vtable::StructArray - pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::dtype_for_stats_table(column_dtype: &vortex_array::dtype::DType, present_stats: &[vortex_array::expr::stats::Stat]) -> vortex_array::dtype::DType -pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::get_stat(&self, stat: vortex_array::expr::stats::Stat) -> vortex_error::VortexResult> - -pub unsafe fn vortex_layout::layouts::zoned::zone_map::ZoneMap::new_unchecked(array: vortex_array::arrays::struct_::vtable::StructArray, stats: alloc::sync::Arc<[vortex_array::expr::stats::Stat]>) -> Self - -pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::present_stats(&self) -> &alloc::sync::Arc<[vortex_array::expr::stats::Stat]> +pub unsafe fn vortex_layout::layouts::zoned::zone_map::ZoneMap::new_unchecked(array: vortex_array::arrays::struct_::vtable::StructArray, zone_len: u64, row_count: u64) -> Self pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::prune(&self, predicate: &vortex_array::expr::expression::Expression, session: &vortex_session::VortexSession) -> vortex_error::VortexResult -pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::to_stats_set(&self, stats: &[vortex_array::expr::stats::Stat], ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult - -pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::try_new(column_dtype: vortex_array::dtype::DType, array: vortex_array::arrays::struct_::vtable::StructArray, stats: alloc::sync::Arc<[vortex_array::expr::stats::Stat]>) -> vortex_error::VortexResult +pub fn vortex_layout::layouts::zoned::zone_map::ZoneMap::try_new(column_dtype: vortex_array::dtype::DType, array: vortex_array::arrays::struct_::vtable::StructArray, stats: alloc::sync::Arc<[vortex_array::expr::stats::Stat]>, zone_len: u64, row_count: u64) -> vortex_error::VortexResult impl core::clone::Clone for vortex_layout::layouts::zoned::zone_map::ZoneMap @@ -876,6 +856,8 @@ pub fn vortex_layout::layouts::zoned::ZonedLayout::nzones(&self) -> usize pub fn vortex_layout::layouts::zoned::ZonedLayout::present_stats(&self) -> &alloc::sync::Arc<[vortex_array::expr::stats::Stat]> +pub fn vortex_layout::layouts::zoned::ZonedLayout::zone_len(&self) -> usize + impl core::clone::Clone for vortex_layout::layouts::zoned::ZonedLayout pub fn vortex_layout::layouts::zoned::ZonedLayout::clone(&self) -> vortex_layout::layouts::zoned::ZonedLayout @@ -1432,6 +1414,12 @@ impl core::fmt::Debug for vortex_layout::session::LayoutSession pub fn vortex_layout::session::LayoutSession::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl vortex_session::SessionVar for vortex_layout::session::LayoutSession + +pub fn vortex_layout::session::LayoutSession::as_any(&self) -> &dyn core::any::Any + +pub fn vortex_layout::session::LayoutSession::as_any_mut(&mut self) -> &mut dyn core::any::Any + pub trait vortex_layout::session::LayoutSessionExt: vortex_session::SessionExt pub fn vortex_layout::session::LayoutSessionExt::layouts(&self) -> vortex_session::Ref<'_, vortex_layout::session::LayoutSession> diff --git a/vortex-layout/src/layouts/file_stats.rs b/vortex-layout/src/layouts/file_stats.rs index f12af8a98fc..0b3205e216f 100644 --- a/vortex-layout/src/layouts/file_stats.rs +++ b/vortex-layout/src/layouts/file_stats.rs @@ -130,14 +130,8 @@ impl FileStatsAccumulator { .lock() .iter_mut() .map(|acc| { - acc.as_stats_table() + acc.as_stats_set(&self.stats, &mut ctx) .vortex_expect("as_stats_table should not fail") - .map(|table| { - table - .to_stats_set(&self.stats, &mut ctx) - .vortex_expect("shouldn't fail to convert table we just created") - }) - .unwrap_or_default() }) .collect() } diff --git a/vortex-layout/src/layouts/zoned/builder.rs b/vortex-layout/src/layouts/zoned/builder.rs index 7f24eaca886..25a6e89f9db 100644 --- a/vortex-layout/src/layouts/zoned/builder.rs +++ b/vortex-layout/src/layouts/zoned/builder.rs @@ -4,6 +4,7 @@ // SPDX-FileCopyrightText: Copyright the Vortex contributors use std::marker::PhantomData; +use std::sync::Arc; use itertools::Itertools; use vortex_array::ArrayRef; @@ -11,14 +12,17 @@ use vortex_array::ExecutionCtx; use vortex_array::IntoArray; use vortex_array::LEGACY_SESSION; use vortex_array::VortexSessionExecute; +use vortex_array::aggregate_fn::fns::sum::sum; use vortex_array::arrays::ConstantArray; use vortex_array::arrays::StructArray; +use vortex_array::arrays::struct_::StructArrayExt; use vortex_array::builders::ArrayBuilder; use vortex_array::builders::BoolBuilder; use vortex_array::builders::builder_with_capacity; use vortex_array::dtype::DType; use vortex_array::dtype::FieldName; use vortex_array::dtype::Nullability; +use vortex_array::dtype::PType; use vortex_array::expr::stats::Precision; use vortex_array::expr::stats::Stat; use vortex_array::expr::stats::StatsProvider; @@ -26,15 +30,14 @@ use vortex_array::scalar::Scalar; use vortex_array::scalar::ScalarTruncation; use vortex_array::scalar::lower_bound; use vortex_array::scalar::upper_bound; +use vortex_array::stats::StatsSet; use vortex_array::validity::Validity; use vortex_buffer::BufferString; use vortex_buffer::ByteBuffer; -use vortex_error::VortexExpect; use vortex_error::VortexResult; use crate::layouts::zoned::schema::MAX_IS_TRUNCATED; use crate::layouts::zoned::schema::MIN_IS_TRUNCATED; -use crate::layouts::zoned::zone_map::ZoneMap; /// Accumulates write-time statistics for each logical zone. pub struct StatsAccumulator { @@ -88,11 +91,7 @@ impl StatsAccumulator { Ok(()) } - /// Finishes the accumulator into a [`ZoneMap`]. - /// - /// Returns `None` if none of the requested statistics can be computed, for example they are - /// not applicable to the column's data type. - pub fn as_stats_table(&mut self) -> VortexResult> { + pub fn as_array(&mut self) -> VortexResult)>> { let mut names = Vec::new(); let mut fields = Vec::new(); let mut stats = Vec::new(); @@ -119,15 +118,50 @@ impl StatsAccumulator { return Ok(None); } - let array = StructArray::try_new(names.into(), fields, self.length, Validity::NonNullable) - .vortex_expect("Failed to create zone map"); - let stats = stats.into(); + let array = StructArray::try_new(names.into(), fields, self.length, Validity::NonNullable)?; + Ok(Some((array, stats.into()))) + } - // SAFETY: `StatsAccumulator` builds the struct fields from `stats_builder_with_capacity` - // using the same field-ordering and truncation-column rules as `stats_table_dtype`. - // The `stats` list is collected in that same sorted order, so the resulting struct array - // matches the expected zoned stats-table dtype by construction. - Ok(Some(unsafe { ZoneMap::new_unchecked(array, stats) })) + /// Returns an aggregated stats set for the table. + pub fn as_stats_set( + &mut self, + stats: &[Stat], + ctx: &mut ExecutionCtx, + ) -> VortexResult { + let mut stats_set = StatsSet::default(); + let Some((array, _)) = self.as_array()? else { + return Ok(stats_set); + }; + + for &stat in stats { + let Some(array) = array.unmasked_field_by_name_opt(stat.name()) else { + continue; + }; + + // Different stats need different aggregations + match stat { + // For stats that are associative, we can just compute them over the stat column + Stat::Min | Stat::Max | Stat::Sum => { + if let Some(s) = array.statistics().compute_stat(stat, ctx)? + && let Some(v) = s.into_value() + { + stats_set.set(stat, Precision::exact(v)) + } + } + // These stats sum up + Stat::NullCount | Stat::NaNCount | Stat::UncompressedSizeInBytes => { + if let Some(sum_value) = sum(array, ctx)? + .cast(&DType::Primitive(PType::U64, Nullability::Nullable))? + .into_value() + { + stats_set.set(stat, Precision::exact(sum_value)); + } + } + // We could implement these aggregations in the future, but for now they're unused + Stat::IsConstant | Stat::IsSorted | Stat::IsStrictSorted => {} + } + } + Ok(stats_set) } } @@ -385,12 +419,9 @@ mod tests { .vortex_expect("push_chunk should succeed for test data"); acc.push_chunk(&builder2.finish(), &mut ctx) .vortex_expect("push_chunk should succeed for test data"); - let stats_table = acc - .as_stats_table() - .unwrap() - .expect("Must have stats table"); + let (stats_table, _) = acc.as_array().unwrap().expect("Must have stats table"); assert_eq!( - stats_table.array().names().as_ref(), + stats_table.names().as_ref(), &[ Stat::Max.name(), MAX_IS_TRUNCATED, @@ -399,7 +430,6 @@ mod tests { ] ); let field1_bool = stats_table - .array() .unmasked_field(1) .clone() .execute::(&mut ctx) @@ -409,7 +439,6 @@ mod tests { BitBuffer::from(vec![false, true]) ); let field3_bool = stats_table - .array() .unmasked_field(3) .clone() .execute::(&mut ctx) @@ -427,12 +456,9 @@ mod tests { let mut acc = StatsAccumulator::new(array.dtype(), &[Stat::Max, Stat::Min, Stat::Sum], 12); acc.push_chunk(&array, &mut ctx) .vortex_expect("push_chunk should succeed for test array"); - let stats_table = acc - .as_stats_table() - .unwrap() - .expect("Must have stats table"); + let (stats_table, _) = acc.as_array().unwrap().expect("Must have stats table"); assert_eq!( - stats_table.array().names().as_ref(), + stats_table.names().as_ref(), &[ Stat::Max.name(), MAX_IS_TRUNCATED, @@ -442,14 +468,12 @@ mod tests { ] ); let field1_bool = stats_table - .array() .unmasked_field(1) .clone() .execute::(&mut ctx) .unwrap(); assert_eq!(field1_bool.to_bit_buffer(), BitBuffer::from(vec![false])); let field3_bool = stats_table - .array() .unmasked_field(3) .clone() .execute::(&mut ctx) diff --git a/vortex-layout/src/layouts/zoned/mod.rs b/vortex-layout/src/layouts/zoned/mod.rs index 18ae57f368f..697e55e968c 100644 --- a/vortex-layout/src/layouts/zoned/mod.rs +++ b/vortex-layout/src/layouts/zoned/mod.rs @@ -201,6 +201,10 @@ impl ZonedLayout { usize::try_from(self.children.child_row_count(1)).vortex_expect("Invalid number of zones") } + pub fn zone_len(&self) -> usize { + self.zone_len + } + /// Returns an array of stats that exist in the layout's data, must be sorted. pub fn present_stats(&self) -> &Arc<[Stat]> { &self.present_stats diff --git a/vortex-layout/src/layouts/zoned/pruning.rs b/vortex-layout/src/layouts/zoned/pruning.rs index 7fccafddebb..99526363813 100644 --- a/vortex-layout/src/layouts/zoned/pruning.rs +++ b/vortex-layout/src/layouts/zoned/pruning.rs @@ -40,6 +40,8 @@ type PredicateCache = Arc>>; pub(super) struct PruningState { zone_count: usize, + row_count: u64, + zone_len: u64, present_stats: Arc<[Stat]>, lazy_children: Arc, session: VortexSession, @@ -57,6 +59,8 @@ impl PruningState { ) -> Self { Self { zone_count: layout.nzones(), + row_count: layout.row_count(), + zone_len: layout.zone_len() as u64, present_stats: Arc::clone(layout.present_stats()), lazy_children, session, @@ -131,7 +135,6 @@ impl PruningState { self.zone_map .get_or_init(move || { let zone_count = self.zone_count; - let present_stats = Arc::clone(&self.present_stats); let zones_eval = self .lazy_children .get(1) @@ -143,13 +146,15 @@ impl PruningState { ) .vortex_expect("Failed construct zone map evaluation"); let session = self.session.clone(); + let zone_len = self.zone_len; + let row_count = self.row_count; async move { let mut ctx = session.create_execution_ctx(); let zones_array = zones_eval.await?.execute::(&mut ctx)?; // SAFETY: zoned layout validation ensures the zones child matches the expected // stats-table schema for `present_stats`. - Ok(unsafe { ZoneMap::new_unchecked(zones_array, present_stats) }) + Ok(unsafe { ZoneMap::new_unchecked(zones_array, zone_len, row_count) }) } .map_err(Arc::new) .boxed() diff --git a/vortex-layout/src/layouts/zoned/reader.rs b/vortex-layout/src/layouts/zoned/reader.rs index 70bad53db9e..e3dc2bf2e00 100644 --- a/vortex-layout/src/layouts/zoned/reader.rs +++ b/vortex-layout/src/layouts/zoned/reader.rs @@ -91,6 +91,10 @@ impl LayoutReader for ZonedReader { &self.name } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn dtype(&self) -> &DType { self.layout.dtype() } @@ -208,10 +212,6 @@ impl LayoutReader for ZonedReader { self.data_child()? .projection_evaluation(row_range, expr, mask) } - - fn as_any(&self) -> &dyn std::any::Any { - self - } } #[cfg(test)] diff --git a/vortex-layout/src/layouts/zoned/writer.rs b/vortex-layout/src/layouts/zoned/writer.rs index 9c895d986d2..7308a62f044 100644 --- a/vortex-layout/src/layouts/zoned/writer.rs +++ b/vortex-layout/src/layouts/zoned/writer.rs @@ -117,7 +117,7 @@ impl LayoutStrategy for ZonedStrategy { chunk .statistics() .compute_all(&stats, &mut session.create_execution_ctx())?; - VortexResult::Ok((sequence_id, chunk)) + Ok((sequence_id, chunk)) }) }) .buffered(self.options.concurrency), @@ -155,7 +155,7 @@ impl LayoutStrategy for ZonedStrategy { ) .await?; - let Some(stats_table) = stats_accumulator.lock().as_stats_table()? else { + let Some((stats_array, stats)) = stats_accumulator.lock().as_array()? else { // If we have no stats (e.g. the DType doesn't support them), then we just return the // child layout. return Ok(data_layout); @@ -163,9 +163,7 @@ impl LayoutStrategy for ZonedStrategy { // We must defer creating the stats table LayoutWriter until now, because the DType of // the table depends on which stats were successfully computed. - let stats_stream = stats_table - .array() - .clone() + let stats_stream = stats_array .into_array() .to_array_stream() .sequenced(eof.split_off()); @@ -174,13 +172,7 @@ impl LayoutStrategy for ZonedStrategy { .write_stream(ctx, Arc::clone(&segment_sink), stats_stream, eof, &session) .await?; - Ok(ZonedLayout::new( - data_layout, - zones_layout, - block_size, - Arc::clone(stats_table.present_stats()), - ) - .into_layout()) + Ok(ZonedLayout::new(data_layout, zones_layout, block_size, stats).into_layout()) } fn buffered_bytes(&self) -> u64 { diff --git a/vortex-layout/src/layouts/zoned/zone_map.rs b/vortex-layout/src/layouts/zoned/zone_map.rs index 9a0173c0035..485fff7ee30 100644 --- a/vortex-layout/src/layouts/zoned/zone_map.rs +++ b/vortex-layout/src/layouts/zoned/zone_map.rs @@ -9,22 +9,22 @@ use vortex_array::ArrayRef; use vortex_array::ExecutionCtx; use vortex_array::IntoArray; use vortex_array::VortexSessionExecute; -use vortex_array::aggregate_fn::fns::sum::sum; +use vortex_array::arrays::ConstantArray; +use vortex_array::arrays::PrimitiveArray; use vortex_array::arrays::StructArray; -use vortex_array::arrays::struct_::StructArrayExt; use vortex_array::dtype::DType; -use vortex_array::dtype::Nullability; -use vortex_array::dtype::PType; use vortex_array::expr::Expression; -use vortex_array::expr::stats::Precision; use vortex_array::expr::stats::Stat; -use vortex_array::stats::StatsSet; +use vortex_array::scalar_fn::internal::row_count::contains_row_count; +use vortex_array::scalar_fn::internal::row_count::substitute_row_count; +use vortex_array::validity::Validity; +use vortex_buffer::buffer; use vortex_error::VortexResult; use vortex_error::vortex_bail; use vortex_mask::Mask; +use vortex_runend::RunEnd; use vortex_session::VortexSession; -pub use crate::layouts::zoned::builder::StatsAccumulator; use crate::layouts::zoned::schema::stats_table_dtype; /// A zone map containing statistics for a column. @@ -35,8 +35,10 @@ use crate::layouts::zoned::schema::stats_table_dtype; pub struct ZoneMap { // The struct array backing the zone map array: StructArray, - // The statistics that are included in the table. - stats: Arc<[Stat]>, + // The length of each zone in the zone map. + zone_len: u64, + // Number of rows that the zone map covers + row_count: u64, } impl ZoneMap { @@ -46,6 +48,8 @@ impl ZoneMap { column_dtype: DType, array: StructArray, stats: Arc<[Stat]>, + zone_len: u64, + row_count: u64, ) -> VortexResult { let expected_dtype = stats_table_dtype(&column_dtype, &stats); if &expected_dtype != array.dtype() { @@ -53,7 +57,7 @@ impl ZoneMap { } // SAFETY: We checked that the array matches the expected stats-table schema. - Ok(unsafe { Self::new_unchecked(array, stats) }) + Ok(unsafe { Self::new_unchecked(array, zone_len, row_count) }) } /// Creates [`ZoneMap`] without validating return array against expected stats. @@ -61,9 +65,12 @@ impl ZoneMap { /// # Safety /// /// Assumes that the input struct array has the correct statistics as fields. Or in other words, - /// the [`DType`] of the input array is equal to the result of `stats_table_dtype`. - pub unsafe fn new_unchecked(array: StructArray, stats: Arc<[Stat]>) -> Self { - Self { array, stats } + pub unsafe fn new_unchecked(array: StructArray, zone_len: u64, row_count: u64) -> Self { + Self { + array, + zone_len, + row_count, + } } /// Returns the [`DType`] of the statistics table given a set of statistics and column [`DType`]. @@ -74,71 +81,65 @@ impl ZoneMap { stats_table_dtype(column_dtype, present_stats) } - /// Returns the underlying [`StructArray`] backing the zone map - pub fn array(&self) -> &StructArray { - &self.array - } + /// Apply a pruning predicate to this zone map. + /// + /// `predicate` should be the result of converting a filter with + /// [`checked_pruning_expr`]. The returned mask has one value per zone, where + /// `true` means the zone cannot contain matching rows and can be skipped. + /// + /// If the predicate contains [`row_count`][vortex_array::scalar_fn::internal::row_count] + /// placeholders, they are replaced after [`ArrayRef::apply`] with per-zone + /// counts derived from `zone_len` and `row_count`. Uniform zones use a + /// [`ConstantArray`]; a short final zone uses a run-end encoded array. + /// + /// [`checked_pruning_expr`]: vortex_array::expr::pruning::checked_pruning_expr + pub fn prune(&self, predicate: &Expression, session: &VortexSession) -> VortexResult { + let mut ctx = session.create_execution_ctx(); + let num_zones = self.array.len(); - /// Returns the list of stats included in the zone map. - pub fn present_stats(&self) -> &Arc<[Stat]> { - &self.stats - } + let applied = self.array.clone().into_array().apply(predicate)?; - /// Returns an aggregated stats set for the table. - pub fn to_stats_set(&self, stats: &[Stat], ctx: &mut ExecutionCtx) -> VortexResult { - let mut stats_set = StatsSet::default(); - for &stat in stats { - let Some(array) = self.get_stat(stat)? else { - continue; - }; - - // Different stats need different aggregations - match stat { - // For stats that are associative, we can just compute them over the stat column - Stat::Min | Stat::Max | Stat::Sum => { - if let Some(s) = array.statistics().compute_stat(stat, ctx)? - && let Some(v) = s.into_value() - { - stats_set.set(stat, Precision::exact(v)) - } - } - // These stats sum up - Stat::NullCount | Stat::NaNCount | Stat::UncompressedSizeInBytes => { - if let Some(sum_value) = sum(&array, ctx)? - .cast(&DType::Primitive(PType::U64, Nullability::Nullable))? - .into_value() - { - stats_set.set(stat, Precision::exact(sum_value)); - } - } - // We could implement these aggregations in the future, but for now they're unused - Stat::IsConstant | Stat::IsSorted | Stat::IsStrictSorted => {} - } + if num_zones == 0 || !contains_row_count(&applied) { + return applied.execute::(&mut ctx); } - Ok(stats_set) + + let row_count_array = row_count_array(self.zone_len, self.row_count, num_zones, &mut ctx)?; + let substituted = substitute_row_count(applied, &row_count_array)?; + substituted.execute::(&mut ctx) } +} - /// Returns the array for a given stat. - pub fn get_stat(&self, stat: Stat) -> VortexResult> { - Ok(self.array.unmasked_field_by_name_opt(stat.name()).cloned()) +/// Build per-zone row counts for a zone map. +/// +/// `zone_len` is the nominal zone size; only the final zone may be shorter. The +/// result is a [`ConstantArray`] for uniform zone sizes, otherwise a two-run +/// run-end encoded array whose trailing run carries the final zone length. +fn row_count_array( + zone_len: u64, + row_count: u64, + num_zones: usize, + ctx: &mut ExecutionCtx, +) -> VortexResult { + let last_zone_len = row_count - zone_len.saturating_mul((num_zones as u64) - 1); + if num_zones == 1 || last_zone_len == zone_len { + return Ok(ConstantArray::new(last_zone_len, num_zones).into_array()); } - /// Apply a pruning predicate against the ZoneMap, yielding a mask indicating which zones can - /// be pruned. - /// - /// The expression provided should be the result of converting an existing `VortexExpr` via - /// [`checked_pruning_expr`][vortex_array::expr::pruning::checked_pruning_expr] into a prunable - /// expression that can be evaluated on a zone map. - /// - /// All zones where the predicate evaluates to `true` can be skipped entirely. - pub fn prune(&self, predicate: &Expression, session: &VortexSession) -> VortexResult { - let mut ctx = session.create_execution_ctx(); - self.array - .clone() - .into_array() - .apply(predicate)? - .execute::(&mut ctx) + let ends = unsafe { + PrimitiveArray::new_unchecked( + buffer![num_zones as u64 - 1, num_zones as u64], + Validity::NonNullable, + ) + } + .into_array(); + let values = unsafe { + PrimitiveArray::new_unchecked(buffer![zone_len, last_zone_len], Validity::NonNullable) } + .into_array(); + + // SAFETY: `ends` are strictly increasing, terminate at `num_zones`, and align one-to-one + // with the non-null run values. + Ok(unsafe { RunEnd::new_unchecked(ends, values, 0, num_zones, ctx) }.into_array()) } #[cfg(test)] @@ -155,6 +156,7 @@ mod tests { use vortex_array::dtype::PType; use vortex_array::expr::gt; use vortex_array::expr::gt_eq; + use vortex_array::expr::is_not_null; use vortex_array::expr::lit; use vortex_array::expr::lt; use vortex_array::expr::pruning::checked_pruning_expr; @@ -207,6 +209,8 @@ mod tests { ]) .unwrap(), Arc::new([Stat::Max, Stat::Min]), + 3, + 10, ) .unwrap(); @@ -237,4 +241,59 @@ mod tests { let mask = zone_map.prune(&pruning_expr, &SESSION).unwrap(); assert_arrays_eq!(mask.into_array(), BoolArray::from_iter([false, true, true])); } + + #[test] + fn row_count_prunes_short_trailing_zone() { + let zone_map = ZoneMap::try_new( + PType::U64.into(), + StructArray::from_fields(&[( + "null_count", + PrimitiveArray::new(buffer![0u64, 0, 2], Validity::AllValid).into_array(), + )]) + .unwrap(), + Arc::new([Stat::NullCount]), + 4, + 10, + ) + .unwrap(); + + let available_stats = + FieldPathSet::from_iter([FieldPath::from_iter([Stat::NullCount.name().into()])]); + let expr = is_not_null(root()); + let (pruning_expr, _) = checked_pruning_expr(&expr, &available_stats).unwrap(); + + let mask = zone_map.prune(&pruning_expr, &SESSION).unwrap(); + assert_arrays_eq!( + mask.into_array(), + BoolArray::from_iter([false, false, true]) + ); + } + + #[test] + fn row_count_prunes_all_null_uniform_zones() { + let zone_map = ZoneMap::try_new( + PType::U64.into(), + StructArray::from_fields(&[( + "null_count", + PrimitiveArray::new(buffer![0u64, 4, 0], Validity::AllValid).into_array(), + )]) + .unwrap(), + Arc::new([Stat::NullCount]), + 4, + 12, + ) + .unwrap(); + + let available_stats = + FieldPathSet::from_iter([FieldPath::from_iter([Stat::NullCount.name().into()])]); + let expr = is_not_null(root()); + let (pruning_expr, _) = checked_pruning_expr(&expr, &available_stats).unwrap(); + + // All three zones have length 4 (total rows = 12). + let mask = zone_map.prune(&pruning_expr, &SESSION).unwrap(); + assert_arrays_eq!( + mask.into_array(), + BoolArray::from_iter([false, true, false]) + ); + } } diff --git a/vortex-layout/src/session.rs b/vortex-layout/src/session.rs index 131115950e4..370fe391ca0 100644 --- a/vortex-layout/src/session.rs +++ b/vortex-layout/src/session.rs @@ -1,8 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use std::any::Any; + use vortex_session::Ref; use vortex_session::SessionExt; +use vortex_session::SessionVar; use vortex_session::registry::Registry; use crate::LayoutEncodingRef; @@ -54,6 +57,15 @@ impl Default for LayoutSession { } } +impl SessionVar for LayoutSession { + fn as_any(&self) -> &dyn Any { + self + } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Extension trait for accessing layout session data. pub trait LayoutSessionExt: SessionExt { /// Returns the layout encoding registry. diff --git a/vortex-python/python/vortex/ray/datasource.py b/vortex-python/python/vortex/ray/datasource.py index b3516490026..966c33b3eaf 100644 --- a/vortex-python/python/vortex/ray/datasource.py +++ b/vortex-python/python/vortex/ray/datasource.py @@ -133,7 +133,7 @@ def _read_task( num_rows=num_rows, size_bytes=None, exec_stats=None, - input_files=paths, + input_files=tuple(paths), ) def read() -> Iterable[pandas.DataFrame]: diff --git a/vortex-python/test/test_datasource.py b/vortex-python/test/test_datasource.py index eece2e7e7de..fc7fc0f492c 100644 --- a/vortex-python/test/test_datasource.py +++ b/vortex-python/test/test_datasource.py @@ -14,13 +14,15 @@ @pytest.fixture(scope="module") def ray_init(): - # https://github.com/ray-project/ray/issues/53848#issuecomment-3056271943 - ray.init( # pyright: ignore[reportUnknownMemberType] - runtime_env={ - "working_dir": None, - "excludes": [".git", ".venv"], - } - ) + # Ray's uv_runtime_env_hook would auto-upload the working directory to + # workers, but vortex-python's compiled _lib extension exceeds Ray's + # 512 MiB upload limit. Disable the hook for these local-mode tests. + # (Ray 2.55 added a string-type validation that broke the previous + # `working_dir: None` workaround from ray-project/ray#53848.) + import ray._private.ray_constants as ray_constants + + ray_constants.RAY_ENABLE_UV_RUN_RUNTIME_ENV = False + _ = ray.init() # pyright: ignore[reportUnknownMemberType] yield None ray.shutdown() # pyright: ignore[reportUnknownMemberType] @@ -53,7 +55,7 @@ def test_vortex_datasource(ray_init, tmpdir_factory): # pyright: ignore[reportU # Without an explicit sort, Ray may reorder rows *even within a single record batch*. ds = ds.sort("index") - tbl = pa.concat_tables(pa.Table.from_pydict(x) for x in ds.iter_batches()) # pyright: ignore[reportArgumentType] + tbl = pa.concat_tables(pa.Table.from_pydict(x) for x in ds.iter_batches()) # pyright: ignore[reportArgumentType, reportUnknownMemberType, reportUnknownVariableType] expected = pa.Table.from_pylist([record(x) for x in range(0, 10)], schema=tbl.schema) assert tbl == expected diff --git a/vortex-session/public-api.lock b/vortex-session/public-api.lock index a63e955f77a..fc1d6c0d421 100644 --- a/vortex-session/public-api.lock +++ b/vortex-session/public-api.lock @@ -239,9 +239,3 @@ pub trait vortex_session::SessionVar: core::any::Any + core::marker::Send + core pub fn vortex_session::SessionVar::as_any(&self) -> &dyn core::any::Any pub fn vortex_session::SessionVar::as_any_mut(&mut self) -> &mut dyn core::any::Any - -impl vortex_session::SessionVar for T - -pub fn T::as_any(&self) -> &dyn core::any::Any - -pub fn T::as_any_mut(&mut self) -> &mut dyn core::any::Any diff --git a/vortex-session/src/lib.rs b/vortex-session/src/lib.rs index 146d8390ac9..baa5f0ef126 100644 --- a/vortex-session/src/lib.rs +++ b/vortex-session/src/lib.rs @@ -83,6 +83,16 @@ struct UnknownPluginPolicy { allow_unknown: bool, } +impl SessionVar for UnknownPluginPolicy { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + /// Trait for accessing and modifying the state of a Vortex session. pub trait SessionExt: Sized + private::Sealed { /// Returns the [`VortexSession`]. @@ -208,21 +218,13 @@ impl Hasher for IdHasher { } /// This trait defines variables that can be stored against a Vortex session. +/// +/// Users should implement this trait for anything that you want to store on a `VortexSession`. pub trait SessionVar: Any + Send + Sync + Debug + 'static { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; } -impl SessionVar for T { - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - // NOTE(ngates): we don't want to expose that the internals of a session is a DashMap, so we have // our own wrapped Ref type. pub struct Ref<'a, T>(dashmap::mapref::one::MappedRef<'a, TypeId, Box, T>); diff --git a/vortex-web/eslint.config.ts b/vortex-web/eslint.config.ts index ecc2fe28df0..8c6a8e00920 100644 --- a/vortex-web/eslint.config.ts +++ b/vortex-web/eslint.config.ts @@ -21,7 +21,8 @@ export default tseslint.config({ ignores: ["dist", "storybook-static"] }, { "react-refresh": reactRefresh, }, rules: { - ...reactHooks.configs.recommended.rules, + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", "react-refresh/only-export-components": [ "warn", { allowConstantExport: true }, diff --git a/vortex-web/package-lock.json b/vortex-web/package-lock.json index 2dccff8bdd4..53ccf765e89 100644 --- a/vortex-web/package-lock.json +++ b/vortex-web/package-lock.json @@ -16,26 +16,26 @@ "react-dom": "^19.1.0" }, "devDependencies": { - "@eslint/js": "^9.25.0", - "@storybook/addon-docs": "^10.3.3", - "@storybook/react-vite": "^10.3.3", - "@tailwindcss/vite": "^4.1.4", + "@eslint/js": "^10.0.1", + "@storybook/addon-docs": "^10.3.5", + "@storybook/react-vite": "^10.3.5", + "@tailwindcss/vite": "^4.2.4", "@types/d3-hierarchy": "^3.1.7", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.2", - "@vitejs/plugin-react": "^4.4.1", - "eslint": "^9.25.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.2.1", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.5.0", - "eslint-plugin-storybook": "^10.3.3", - "globals": "^16.0.0", - "prettier": "^3.8.1", - "storybook": "^10.3.3", - "tailwindcss": "^4.1.4", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "eslint-plugin-storybook": "^10.3.5", + "globals": "^17.5.0", + "prettier": "^3.8.3", + "storybook": "^10.3.5", + "tailwindcss": "^4.2.4", "typescript": "~6.0.0", - "typescript-eslint": "^8.30.1", - "vite": "^6.3.2" + "typescript-eslint": "^8.59.0", + "vite": "^8.0.10" } }, "node_modules/@adobe/css-tools": { @@ -177,16 +177,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -247,38 +237,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/runtime": { "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", @@ -338,6 +296,40 @@ "node": ">=6.9.0" } }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.7", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", @@ -823,118 +815,89 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", - "minimatch": "^3.1.5" + "minimatch": "^10.2.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.2.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@humanfs/core": { @@ -1091,54 +1054,39 @@ "react": ">=16" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" + "@tybys/wasm-util": "^0.10.1" }, - "engines": { - "node": ">=14.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", - "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", - "cpu": [ - "arm" - ], + "node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "funding": { + "url": "https://github.com/sponsors/Boshen" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", - "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", "cpu": [ "arm64" ], @@ -1147,12 +1095,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", - "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", "cpu": [ "arm64" ], @@ -1161,12 +1112,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", - "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", "cpu": [ "x64" ], @@ -1175,26 +1129,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", - "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", - "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", "cpu": [ "x64" ], @@ -1203,46 +1146,32 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", - "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "glibc" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", - "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", "cpu": [ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", - "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "cpu": [ "arm64" ], @@ -1254,12 +1183,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", - "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", "cpu": [ "arm64" ], @@ -1271,46 +1203,15 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", - "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", - "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "musl" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", - "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", "cpu": [ "ppc64" ], @@ -1322,31 +1223,17 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", - "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "musl" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", - "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", "cpu": [ - "riscv64" + "s390x" ], "dev": true, "libc": [ @@ -1356,31 +1243,17 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", - "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", - "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "cpu": [ - "s390x" + "x64" ], "dev": true, "libc": [ @@ -1390,60 +1263,71 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", - "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", "cpu": [ "x64" ], "dev": true, "libc": [ - "glibc" + "musl" ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", - "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", "cpu": [ - "x64" + "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ - "linux" - ] + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", - "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", "cpu": [ - "x64" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "openbsd" - ] + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", - "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", "cpu": [ "arm64" ], @@ -1451,64 +1335,58 @@ "license": "MIT", "optional": true, "os": [ - "openharmony" - ] + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", - "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", - "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", - "cpu": [ - "ia32" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", - "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", - "cpu": [ - "x64" - ], + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", - "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", - "cpu": [ - "x64" - ], + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } }, "node_modules/@storybook/addon-docs": { "version": "10.3.5", @@ -2156,6 +2034,17 @@ "@testing-library/dom": ">=7.21.4" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -2253,6 +2142,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -2498,45 +2394,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", @@ -2592,38 +2449,30 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "@rolldown/pluginutils": "1.0.0-rc.7" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } } }, "node_modules/@vitest/expect": { @@ -2715,9 +2564,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -2777,13 +2626,6 @@ "arrow2csv": "bin/arrow2csv.js" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, "node_modules/aria-query": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", @@ -2827,11 +2669,14 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/baseline-browser-mapping": { "version": "2.10.21", @@ -2847,14 +2692,16 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/browserslist": { @@ -2907,16 +2754,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001790", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", @@ -3052,13 +2889,6 @@ "node": ">=12.20.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -3330,33 +3160,30 @@ } }, "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", + "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", - "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -3366,8 +3193,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -3375,7 +3201,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" @@ -3406,16 +3232,23 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-react-refresh": { @@ -3443,48 +3276,50 @@ } }, "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "eslint-visitor-keys": "^5.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3736,49 +3571,10 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "version": "17.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz", + "integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==", "dev": true, "license": "MIT", "engines": { @@ -3817,6 +3613,23 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3827,23 +3640,6 @@ "node": ">= 4" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3978,19 +3774,6 @@ "dev": true, "license": "MIT" }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -4365,13 +4148,6 @@ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/loupe": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", @@ -4421,16 +4197,19 @@ } }, "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -4562,19 +4341,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4815,16 +4581,6 @@ "license": "MIT", "peer": true }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/recast": { "version": "0.23.11", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", @@ -4891,60 +4647,46 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/rollup": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", - "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "node_modules/rolldown": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.2", - "@rollup/rollup-android-arm64": "4.60.2", - "@rollup/rollup-darwin-arm64": "4.60.2", - "@rollup/rollup-darwin-x64": "4.60.2", - "@rollup/rollup-freebsd-arm64": "4.60.2", - "@rollup/rollup-freebsd-x64": "4.60.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", - "@rollup/rollup-linux-arm-musleabihf": "4.60.2", - "@rollup/rollup-linux-arm64-gnu": "4.60.2", - "@rollup/rollup-linux-arm64-musl": "4.60.2", - "@rollup/rollup-linux-loong64-gnu": "4.60.2", - "@rollup/rollup-linux-loong64-musl": "4.60.2", - "@rollup/rollup-linux-ppc64-gnu": "4.60.2", - "@rollup/rollup-linux-ppc64-musl": "4.60.2", - "@rollup/rollup-linux-riscv64-gnu": "4.60.2", - "@rollup/rollup-linux-riscv64-musl": "4.60.2", - "@rollup/rollup-linux-s390x-gnu": "4.60.2", - "@rollup/rollup-linux-x64-gnu": "4.60.2", - "@rollup/rollup-linux-x64-musl": "4.60.2", - "@rollup/rollup-openbsd-x64": "4.60.2", - "@rollup/rollup-openharmony-arm64": "4.60.2", - "@rollup/rollup-win32-arm64-msvc": "4.60.2", - "@rollup/rollup-win32-ia32-msvc": "4.60.2", - "@rollup/rollup-win32-x64-gnu": "4.60.2", - "@rollup/rollup-win32-x64-msvc": "4.60.2", - "fsevents": "~2.3.2" - } + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "dev": true, + "license": "MIT" }, "node_modules/run-applescript": { "version": "7.1.0", @@ -5091,19 +4833,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5385,24 +5114,23 @@ } }, "node_modules/vite": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", - "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -5411,14 +5139,15 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -5427,13 +5156,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { + "optional": true + }, + "jiti": { "optional": true }, - "lightningcss": { + "less": { "optional": true }, "sass": { @@ -5459,490 +5191,6 @@ } } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", @@ -6042,6 +5290,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/vortex-web/package.json b/vortex-web/package.json index b0b1d825faa..9f21562641d 100644 --- a/vortex-web/package.json +++ b/vortex-web/package.json @@ -27,25 +27,25 @@ "react-dom": "^19.1.0" }, "devDependencies": { - "@eslint/js": "^9.25.0", - "@storybook/addon-docs": "^10.3.3", - "@storybook/react-vite": "^10.3.3", - "@tailwindcss/vite": "^4.1.4", + "@eslint/js": "^10.0.1", + "@storybook/addon-docs": "^10.3.5", + "@storybook/react-vite": "^10.3.5", + "@tailwindcss/vite": "^4.2.4", "@types/d3-hierarchy": "^3.1.7", - "@types/react": "^19.1.2", - "@types/react-dom": "^19.1.2", - "@vitejs/plugin-react": "^4.4.1", - "eslint": "^9.25.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.2.1", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.5.0", - "eslint-plugin-storybook": "^10.3.3", - "globals": "^16.0.0", - "prettier": "^3.8.1", - "storybook": "^10.3.3", - "tailwindcss": "^4.1.4", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "eslint-plugin-storybook": "^10.3.5", + "globals": "^17.5.0", + "prettier": "^3.8.3", + "storybook": "^10.3.5", + "tailwindcss": "^4.2.4", "typescript": "~6.0.0", - "typescript-eslint": "^8.30.1", - "vite": "^6.3.2" + "typescript-eslint": "^8.59.0", + "vite": "^8.0.10" } }