diff --git a/Cargo.lock b/Cargo.lock index f2e4e1df9..0181cc45d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", + "const-random", "getrandom 0.3.4", "once_cell", "version_check", @@ -125,6 +126,108 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arrow-array" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8955af33b25f3b175ee10af580577280b4bd01f7e823d94c7cdef7cf8c9aef" +dependencies = [ + "ahash", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "chrono-tz", + "half", + "hashbrown 0.16.1", + "num-complex", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-buffer" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c697ddca96183182f35b3a18e50b9110b11e916d7b7799cbfd4d34662f2c56c2" +dependencies = [ + "bytes", + "half", + "num-bigint", + "num-traits", +] + +[[package]] +name = "arrow-cast" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "646bbb821e86fd57189c10b4fcdaa941deaf4181924917b0daa92735baa6ada5" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num-traits", + "ryu", +] + +[[package]] +name = "arrow-data" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fdd994a9d28e6365aa78e15da3f3950c0fdcea6b963a12fa1c391afb637b304" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-ord" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d8f1870e03d4cbed632959498bcc84083b5a24bded52905ae1695bd29da45b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-schema" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c872d36b7bf2a6a6a2b40de9156265f0242910791db366a2c17476ba8330d68" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "arrow-select" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bf3e3efbd1278f770d67e5dc410257300b161b93baedb3aae836144edcaf4b" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num-traits", +] + [[package]] name = "assert_fs" version = "1.1.3" @@ -184,6 +287,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -198,9 +310,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" -version = "1.8.12" +version = "1.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96571e6996817bf3d58f6b569e4b9fd2e9d2fcf9f7424eed07b2ce9bb87535e5" +checksum = "11493b0bad143270fb8ad284a096dd529ba91924c5409adeac856cc1bf047dbc" dependencies = [ "aws-credential-types", "aws-runtime", @@ -208,7 +320,7 @@ dependencies = [ "aws-sdk-ssooidc", "aws-sdk-sts", "aws-smithy-async", - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -218,7 +330,7 @@ dependencies = [ "fastrand", "hex", "http 1.4.0", - "ring", + "sha1", "time", "tokio", "tracing", @@ -240,9 +352,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.15.2" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" dependencies = [ "aws-lc-sys", "zeroize", @@ -250,9 +362,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.35.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" dependencies = [ "cc", "cmake", @@ -262,23 +374,26 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.18" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959dab27ce613e6c9658eb3621064d0e2027e5f2acb65bc526a43577facea557" +checksum = "5fc0651c57e384202e47153c1260b84a9936e19803d747615edf199dc3b98d17" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", + "bytes-utils", "fastrand", "http 0.2.12", + "http 1.4.0", "http-body 0.4.6", + "http-body 1.0.1", "percent-encoding", "pin-project-lite", "tracing", @@ -287,9 +402,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.120.0" +version = "1.125.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06673901e961f20fa8d7da907da48f7ad6c1b383e3726c22bd418900f015abe1" +checksum = "223f5c95650d9557925a91f4c2db3def189e8f659452134a29e5cd2d37d708ed" dependencies = [ "aws-credential-types", "aws-runtime", @@ -297,7 +412,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-checksums", "aws-smithy-eventstream", - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-json", "aws-smithy-observability", "aws-smithy-runtime", @@ -311,7 +426,7 @@ dependencies = [ "hmac", "http 0.2.12", "http 1.4.0", - "http-body 0.4.6", + "http-body 1.0.1", "lru", "percent-encoding", "regex-lite", @@ -322,15 +437,16 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.91.0" +version = "1.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee6402a36f27b52fe67661c6732d684b2635152b676aa2babbfb5204f99115d" +checksum = "f64a6eded248c6b453966e915d32aeddb48ea63ad17932682774eb026fbef5b1" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -338,21 +454,23 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", + "http 1.4.0", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-ssooidc" -version = "1.93.0" +version = "1.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45a7f750bbd170ee3677671ad782d90b894548f4e4ae168302c57ec9de5cb3e" +checksum = "db96d720d3c622fcbe08bae1c4b04a72ce6257d8b0584cb5418da00ae20a344f" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -360,21 +478,23 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", + "http 1.4.0", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-sts" -version = "1.95.0" +version = "1.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55542378e419558e6b1f398ca70adb0b2088077e79ad9f14eb09441f2f7b2164" +checksum = "fafbdda43b93f57f699c5dfe8328db590b967b8a820a13ccdd6687355dfcc7ca" dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-json", + "aws-smithy-observability", "aws-smithy-query", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -383,19 +503,20 @@ dependencies = [ "aws-types", "fastrand", "http 0.2.12", + "http 1.4.0", "regex-lite", "tracing", ] [[package]] name = "aws-sigv4" -version = "1.3.7" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e523e1c4e8e7e8ff219d732988e22bfeae8a1cafdbe6d9eca1546fa080be7c" +checksum = "b0b660013a6683ab23797778e21f1f854744fdf05f68204b4cca4c8c04b5d1f4" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", @@ -428,17 +549,18 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.63.13" +version = "0.64.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23374b9170cbbcc6f5df8dc5ebb9b6c5c28a3c8f599f0e8b8b10eb6f4a5c6e74" +checksum = "6750f3dd509b0694a4377f0293ed2f9630d710b1cebe281fa8bac8f099f88bc6" dependencies = [ - "aws-smithy-http 0.62.6", + "aws-smithy-http", "aws-smithy-types", "bytes", "crc-fast", "hex", - "http 0.2.12", - "http-body 0.4.6", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", "md-5", "pin-project-lite", "sha1", @@ -448,43 +570,22 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.14" +version = "0.60.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc12f8b310e38cad85cf3bef45ad236f470717393c613266ce0a89512286b650" +checksum = "faf09d74e5e32f76b8762da505a3cd59303e367a664ca67295387baa8c1d7548" dependencies = [ "aws-smithy-types", "bytes", "crc32fast", ] -[[package]] -name = "aws-smithy-http" -version = "0.62.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" -dependencies = [ - "aws-smithy-eventstream", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "bytes-utils", - "futures-core", - "futures-util", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "percent-encoding", - "pin-project-lite", - "pin-utils", - "tracing", -] - [[package]] name = "aws-smithy-http" version = "0.63.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231" dependencies = [ + "aws-smithy-eventstream", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", @@ -510,7 +611,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "h2 0.3.27", - "h2 0.4.12", + "h2 0.4.13", "http 0.2.12", "http 1.4.0", "http-body 0.4.6", @@ -521,7 +622,7 @@ dependencies = [ "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-native-certs", "rustls-pki-types", "tokio", @@ -532,9 +633,9 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.61.9" +version = "0.62.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" +checksum = "9648b0bb82a2eedd844052c6ad2a1a822d1f8e3adee5fbf668366717e428856a" dependencies = [ "aws-smithy-types", ] @@ -550,9 +651,9 @@ dependencies = [ [[package]] name = "aws-smithy-query" -version = "0.60.9" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae5d689cf437eae90460e944a58b5668530d433b4ff85789e69d2f2a556e057d" +checksum = "1a56d79744fb3edb5d722ef79d86081e121d3b9422cb209eb03aea6aa4f21ebd" dependencies = [ "aws-smithy-types", "urlencoding", @@ -565,7 +666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028999056d2d2fd58a697232f9eec4a643cf73a71cf327690a7edad1d2af2110" dependencies = [ "aws-smithy-async", - "aws-smithy-http 0.63.6", + "aws-smithy-http", "aws-smithy-http-client", "aws-smithy-observability", "aws-smithy-runtime-api", @@ -640,18 +741,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.13" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57" +checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.11" +version = "1.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" +checksum = "47c8323699dd9b3c8d5b3c13051ae9cdef58fd179957c882f8374dd8725962d9" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -732,9 +833,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.8.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bit-set" @@ -759,9 +860,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -795,9 +896,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "byteorder" @@ -832,9 +933,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.51" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "jobserver", @@ -879,6 +980,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -961,6 +1072,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "comfy-table" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" +dependencies = [ + "unicode-segmentation", + "unicode-width 0.2.2", +] + [[package]] name = "console" version = "0.16.2" @@ -980,6 +1101,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1206,9 +1347,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", "serde_core", @@ -1366,18 +1507,18 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", ] [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", @@ -1393,9 +1534,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" dependencies = [ "serde", "serde_core", @@ -1436,9 +1577,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flatbuffers" @@ -1446,7 +1587,7 @@ version = "25.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "rustc_version", ] @@ -1630,9 +1771,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -1650,20 +1791,20 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "rand_core 0.10.0", "wasip2", "wasip3", @@ -1700,7 +1841,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "ignore", "walkdir", ] @@ -1740,7 +1881,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util 0.7.18", @@ -1749,9 +1890,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -1759,7 +1900,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.4.0", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util 0.7.18", @@ -1774,6 +1915,7 @@ checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "num-traits", "zerocopy", ] @@ -1955,7 +2097,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.12", + "h2 0.4.13", "http 1.4.0", "http-body 1.0.1", "httparse", @@ -1992,7 +2134,7 @@ dependencies = [ "http 1.4.0", "hyper 1.8.1", "hyper-util", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-native-certs", "rustls-pki-types", "tokio", @@ -2032,14 +2174,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", - "futures-core", "futures-util", "http 1.4.0", "http-body 1.0.1", @@ -2048,8 +2189,8 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", - "system-configuration 0.6.1", + "socket2 0.6.3", + "system-configuration 0.7.0", "tokio", "tower-service", "tracing", @@ -2058,9 +2199,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2085,6 +2226,7 @@ name = "icechunk" version = "2.0.0-alpha.3" dependencies = [ "anyhow", + "arrow-array", "assert_fs", "async-recursion", "async-stream", @@ -2159,6 +2301,7 @@ dependencies = [ name = "icechunk-python" version = "2.0.0-alpha.3" dependencies = [ + "arrow-array", "async-stream", "async-trait", "bytes", @@ -2169,6 +2312,7 @@ dependencies = [ "itertools 0.14.0", "miette", "pyo3", + "pyo3-arrow", "pyo3-async-runtimes", "pyo3-bytes", "rand 0.10.0", @@ -2324,9 +2468,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -2345,18 +2489,18 @@ dependencies = [ [[package]] name = "inventory" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +checksum = "009ae045c87e7082cb72dab0ccd01ae075dd00141ddc108f43a0ea150a9e7227" dependencies = [ "rustversion", ] [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" @@ -2416,9 +2560,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -2436,19 +2580,81 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + [[package]] name = "libc" -version = "0.2.182" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libm" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" dependencies = [ - "bitflags 2.10.0", "libc", ] @@ -2517,6 +2723,16 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "md-5" version = "0.10.6" @@ -2529,9 +2745,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -2622,21 +2838,36 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cdede44f9a69cab2899a2049e2c3bd49bf911a157f6a3353d4a91c61abbce44" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", "openssl", - "openssl-probe 0.1.6", + "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] +[[package]] +name = "ndarray" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + [[package]] name = "noxious" version = "0.1.1" @@ -2679,6 +2910,25 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.0" @@ -2701,6 +2951,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2724,6 +2975,23 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "numpy" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aac2e6a6e4468ffa092ad43c39b81c79196c2bb773b8db4085f695efe3bba17" +dependencies = [ + "half", + "libc", + "ndarray", + "num-complex", + "num-integer", + "num-traits", + "pyo3", + "pyo3-build-config", + "rustc-hash", +] + [[package]] name = "object" version = "0.37.3" @@ -2795,7 +3063,7 @@ version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "foreign-types", "libc", @@ -2817,15 +3085,9 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-probe" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" @@ -2853,9 +3115,9 @@ checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "owo-colors" -version = "4.2.3" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] name = "p256" @@ -2907,20 +3169,38 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", @@ -2929,9 +3209,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -2991,9 +3271,18 @@ checksum = "4c2749dcd0984ec1be3c01001bb1d83623a58c3c0049a99b9afec61464fa98e7" [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +dependencies = [ + "portable-atomic", +] [[package]] name = "potential_utf" @@ -3021,9 +3310,9 @@ dependencies = [ [[package]] name = "predicates" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" dependencies = [ "anstyle", "difflib", @@ -3032,15 +3321,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" [[package]] name = "predicates-tree" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" dependencies = [ "predicates-core", "termtree", @@ -3078,18 +3367,18 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.23.10+spec-1.0.0", + "toml_edit 0.25.4+spec-1.1.0", ] [[package]] name = "proc-macro2" -version = "1.0.104" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -3102,7 +3391,7 @@ checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.10.0", + "bitflags 2.11.0", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -3129,6 +3418,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d" dependencies = [ "chrono", + "chrono-tz", + "indexmap 2.13.0", "indoc", "inventory", "libc", @@ -3141,6 +3432,27 @@ dependencies = [ "unindent", ] +[[package]] +name = "pyo3-arrow" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b9f03cb749b0326951ebb30e39eda2f32b0b9205dce67e947e65779b8faffc" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "chrono", + "chrono-tz", + "half", + "indexmap 2.13.0", + "numpy", + "pyo3", + "thiserror 1.0.69", +] + [[package]] name = "pyo3-async-runtimes" version = "0.27.0" @@ -3248,8 +3560,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.35", - "socket2 0.6.1", + "rustls 0.23.37", + "socket2 0.6.3", "thiserror 2.0.18", "tokio", "tracing", @@ -3258,9 +3570,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", "getrandom 0.3.4", @@ -3268,7 +3580,7 @@ dependencies = [ "rand 0.9.2", "ring", "rustc-hash", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-pki-types", "slab", "thiserror 2.0.18", @@ -3286,7 +3598,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2 0.6.3", "tracing", "windows-sys 0.60.2", ] @@ -3306,6 +3618,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -3324,7 +3642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3334,7 +3652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" dependencies = [ "chacha20", - "getrandom 0.4.1", + "getrandom 0.4.2", "rand_core 0.10.0", ] @@ -3355,7 +3673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -3364,14 +3682,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -3388,9 +3706,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.11.0" @@ -3417,7 +3741,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -3426,7 +3750,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 2.0.18", ] @@ -3465,9 +3789,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3476,15 +3800,15 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "relative-path" @@ -3543,7 +3867,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.12", + "h2 0.4.13", "http 1.4.0", "http-body 1.0.1", "http-body-util", @@ -3558,7 +3882,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-native-certs", "rustls-pki-types", "serde", @@ -3599,7 +3923,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -3654,7 +3978,7 @@ checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" dependencies = [ "cfg-if", "glob", - "proc-macro-crate 3.4.0", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", "regex", @@ -3677,9 +4001,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -3702,7 +4026,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys", @@ -3723,15 +4047,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] @@ -3742,10 +4066,10 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe 0.2.0", + "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework", ] [[package]] @@ -3759,9 +4083,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -3779,9 +4103,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "aws-lc-rs", "ring", @@ -3809,9 +4133,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -3824,9 +4148,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ "windows-sys 0.61.2", ] @@ -3845,9 +4169,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ "dyn-clone", "ref-cast", @@ -3893,24 +4217,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" -dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3919,9 +4230,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -4008,9 +4319,9 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.12.1", + "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.2.0", + "schemars 1.2.1", "serde_core", "serde_json", "serde_with_macros", @@ -4035,7 +4346,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4db627b98b36d4203a7b458cf3573730f2bb591b28871d916dfa9efabfd41f" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "ryu", "serde", @@ -4105,11 +4416,17 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -4129,12 +4446,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4276,11 +4593,11 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -4307,9 +4624,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tempfile" @@ -4318,7 +4635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.4.1", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -4465,6 +4782,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -4511,16 +4837,16 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2 0.6.3", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", @@ -4553,7 +4879,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.35", + "rustls 0.23.37", "tokio", ] @@ -4593,9 +4919,9 @@ checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.0.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" dependencies = [ "serde_core", ] @@ -4606,21 +4932,21 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "toml_datetime 0.6.11", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" dependencies = [ - "indexmap 2.12.1", - "toml_datetime 0.7.5+spec-1.1.0", + "indexmap 2.13.0", + "toml_datetime 1.0.0+spec-1.1.0", "toml_parser", - "winnow 0.7.14", + "winnow 0.7.15", ] [[package]] @@ -4629,14 +4955,14 @@ version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ - "winnow 0.7.14", + "winnow 0.7.15", ] [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -4653,7 +4979,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytes", "futures-util", "http 1.4.0", @@ -4805,15 +5131,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-linebreak" @@ -4821,6 +5147,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.1.14" @@ -4894,7 +5226,7 @@ version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ - "getrandom 0.4.1", + "getrandom 0.4.2", "js-sys", "wasm-bindgen", ] @@ -4988,11 +5320,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen 0.46.0", + "wit-bindgen", ] [[package]] @@ -5001,14 +5333,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -5019,11 +5351,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -5032,9 +5365,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5042,9 +5375,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", @@ -5055,9 +5388,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] @@ -5079,7 +5412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.12.1", + "indexmap 2.13.0", "wasm-encoder", "wasmparser", ] @@ -5103,17 +5436,17 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "hashbrown 0.15.5", - "indexmap 2.12.1", + "indexmap 2.13.0", "semver", ] [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -5131,9 +5464,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -5472,9 +5805,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] @@ -5489,12 +5822,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - [[package]] name = "wit-bindgen" version = "0.51.0" @@ -5523,7 +5850,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap 2.12.1", + "indexmap 2.13.0", "prettyplease", "syn 2.0.117", "wasm-metadata", @@ -5553,8 +5880,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.10.0", - "indexmap 2.12.1", + "bitflags 2.11.0", + "indexmap 2.13.0", "log", "serde", "serde_derive", @@ -5573,7 +5900,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.12.1", + "indexmap 2.13.0", "log", "semver", "serde", @@ -5626,18 +5953,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", @@ -5706,9 +6033,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.2" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zstd" diff --git a/icechunk-python/Cargo.toml b/icechunk-python/Cargo.toml index a8a55a1f7..679b41155 100644 --- a/icechunk-python/Cargo.toml +++ b/icechunk-python/Cargo.toml @@ -22,8 +22,10 @@ crate-type = ["cdylib"] bytes = "1.11.1" chrono = { version = "0.4.44" } futures = "0.3.32" -icechunk = { path = "../icechunk", version = "2.0.0-alpha.3", features = ["logs"] } +icechunk = { path = "../icechunk", version = "2.0.0-alpha.3", features = ["logs", "arrow"] } itertools = "0.14.0" +pyo3-arrow = "0.15" +arrow-array = "57" pyo3 = { version = "0.27.2", features = [ "chrono", "experimental-async", diff --git a/icechunk-python/python/icechunk/_icechunk_python.pyi b/icechunk-python/python/icechunk/_icechunk_python.pyi index 81682e1de..e08740398 100644 --- a/icechunk-python/python/icechunk/_icechunk_python.pyi +++ b/icechunk-python/python/icechunk/_icechunk_python.pyi @@ -11,6 +11,8 @@ from collections.abc import ( from enum import Enum from typing import Any, TypeAlias, final +import pyarrow as pa + class S3Options: """Options for accessing an S3-compatible storage backend""" def __new__( @@ -2206,6 +2208,28 @@ class PyStore: chunks: list[VirtualChunkSpec], validate_containers: bool, ) -> list[tuple[int, ...]] | None: ... + def set_virtual_refs_arr( + self, + array_path: str, + chunk_grid_shape: list[int], + locations: pa.StringArray, + offsets: pa.UInt64Array, + lengths: pa.UInt64Array, + arr_offset: tuple[int, ...] | None = None, + checksum: datetime.datetime | str | None = None, + validate_containers: bool = True, + ) -> list[tuple[int, ...]] | None: ... + async def set_virtual_refs_arr_async( + self, + array_path: str, + chunk_grid_shape: list[int], + locations: pa.StringArray, + offsets: pa.UInt64Array, + lengths: pa.UInt64Array, + arr_offset: tuple[int, ...] | None = None, + checksum: datetime.datetime | str | None = None, + validate_containers: bool = True, + ) -> list[tuple[int, ...]] | None: ... async def delete(self, key: str) -> None: ... async def delete_dir(self, prefix: str) -> None: ... @property diff --git a/icechunk-python/python/icechunk/store.py b/icechunk-python/python/icechunk/store.py index a0ab1a958..c1f522bd8 100644 --- a/icechunk-python/python/icechunk/store.py +++ b/icechunk-python/python/icechunk/store.py @@ -15,6 +15,8 @@ from zarr.core.sync import SyncMixin if TYPE_CHECKING: + import pyarrow as pa + from icechunk import Session @@ -352,6 +354,166 @@ async def set_virtual_refs_async( array_path, chunks, validate_containers ) + def set_virtual_refs_arr( + self, + array_path: str, + chunk_grid_shape: tuple[int, ...], + locations: "pa.StringArray", + offsets: "pa.UInt64Array", + lengths: "pa.UInt64Array", + *, + arr_offset: tuple[int, ...] | None = None, + checksum: datetime | str | None = None, + validate_containers: bool = True, + ) -> list[tuple[int, ...]] | None: + """Store multiple virtual references using Arrow arrays. + + This method is significantly faster than set_virtual_refs for large + numbers of references as it uses Arrow's zero-copy FFI to avoid + creating Python objects per chunk. + + Parameters + ---------- + array_path : str + The path to the array inside the Zarr store. + Example: "/groupA/groupB/outputs/my-array" + chunk_grid_shape : tuple[int, ...] + Shape of the chunk grid. The product must equal the length of the arrays. + Arrays are assumed to be flattened in C (row-major) order. + locations : pa.StringArray + PyArrow StringArray of URLs to external files containing chunk data + offsets : pa.UInt64Array + PyArrow UInt64Array of byte offsets within each file + lengths : pa.UInt64Array + PyArrow UInt64Array of byte lengths of each chunk + arr_offset : tuple[int, ...] | None + Optional offset to add to computed chunk indices. Useful for append + operations where new chunks should be written at an offset from (0,0,...). + Must have the same length as chunk_grid_shape. Default is None. + checksum : datetime | str | None + Optional checksum for all chunks. Can be a datetime (last modified time) + or a string (ETag). Default is None. + validate_containers : bool + If True, validate that locations match registered virtual chunk containers. + Default is True. + + Returns + ------- + list[tuple[int, ...]] | None + If all virtual references were successfully updated, returns None. + If there were validation errors, returns the chunk indices of all failed references. + + Notes + ----- + This method requires PyArrow to be installed. The arrays are passed to + Rust via Arrow's zero-copy FFI, making this much more efficient than + creating millions of VirtualChunkSpec Python objects. + + Example + ------- + >>> import pyarrow as pa + >>> locations = pa.array(["s3://bucket/file1.nc", "s3://bucket/file2.nc"]) + >>> offsets = pa.array([0, 1000], type=pa.uint64()) + >>> lengths = pa.array([1000, 1000], type=pa.uint64()) + >>> store.set_virtual_refs_arr( + ... "/data", + ... chunk_grid_shape=(2,), + ... locations=locations, + ... offsets=offsets, + ... lengths=lengths, + ... ) + """ + return self._store.set_virtual_refs_arr( + array_path, + list(chunk_grid_shape), + locations, + offsets, + lengths, + list(arr_offset) if arr_offset is not None else None, + checksum, + validate_containers, + ) + + async def set_virtual_refs_arr_async( + self, + array_path: str, + chunk_grid_shape: tuple[int, ...], + locations: "pa.StringArray", + offsets: "pa.UInt64Array", + lengths: "pa.UInt64Array", + *, + arr_offset: tuple[int, ...] | None = None, + checksum: datetime | str | None = None, + validate_containers: bool = True, + ) -> list[tuple[int, ...]] | None: + """Store multiple virtual references using Arrow arrays (async version). + + This method is significantly faster than set_virtual_refs for large + numbers of references as it uses Arrow's zero-copy FFI to avoid + creating Python objects per chunk. + + Parameters + ---------- + array_path : str + The path to the array inside the Zarr store. + Example: "/groupA/groupB/outputs/my-array" + chunk_grid_shape : tuple[int, ...] + Shape of the chunk grid. The product must equal the length of the arrays. + Arrays are assumed to be flattened in C (row-major) order. + locations : pa.StringArray + PyArrow StringArray of URLs to external files containing chunk data + offsets : pa.UInt64Array + PyArrow UInt64Array of byte offsets within each file + lengths : pa.UInt64Array + PyArrow UInt64Array of byte lengths of each chunk + arr_offset : tuple[int, ...] | None + Optional offset to add to computed chunk indices. Useful for append + operations where new chunks should be written at an offset from (0,0,...). + Must have the same length as chunk_grid_shape. Default is None. + checksum : datetime | str | None + Optional checksum for all chunks. Can be a datetime (last modified time) + or a string (ETag). Default is None. + validate_containers : bool + If True, validate that locations match registered virtual chunk containers. + Default is True. + + Returns + ------- + list[tuple[int, ...]] | None + If all virtual references were successfully updated, returns None. + If there were validation errors, returns the chunk indices of all failed references. + + Notes + ----- + This method requires PyArrow to be installed. The arrays are passed to + Rust via Arrow's zero-copy FFI, making this much more efficient than + creating millions of VirtualChunkSpec Python objects. + + Example + ------- + >>> import pyarrow as pa + >>> locations = pa.array(["s3://bucket/file1.nc", "s3://bucket/file2.nc"]) + >>> offsets = pa.array([0, 1000], type=pa.uint64()) + >>> lengths = pa.array([1000, 1000], type=pa.uint64()) + >>> await store.set_virtual_refs_arr_async( + ... "/data", + ... chunk_grid_shape=(2,), + ... locations=locations, + ... offsets=offsets, + ... lengths=lengths, + ... ) + """ + return await self._store.set_virtual_refs_arr_async( + array_path, + list(chunk_grid_shape), + locations, + offsets, + lengths, + list(arr_offset) if arr_offset is not None else None, + checksum, + validate_containers, + ) + async def delete(self, key: str) -> None: """Remove a key from the store diff --git a/icechunk-python/src/store.rs b/icechunk-python/src/store.rs index 7d7200bad..c2068cee6 100644 --- a/icechunk-python/src/store.rs +++ b/icechunk-python/src/store.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, sync::Arc}; +use arrow_array::{Array, StringArray, UInt64Array}; use chrono::Utc; use futures::{StreamExt, TryStreamExt}; use icechunk::{ @@ -11,6 +12,7 @@ use icechunk::{ storage::ETag, store::{SetVirtualRefsResult, StoreError, StoreErrorKind}, }; +use pyo3_arrow::PyArray; use itertools::Itertools as _; use pyo3::{ conversion::IntoPyObjectExt, @@ -484,6 +486,189 @@ impl PyStore { ) } + /// Set virtual references using Arrow arrays (sync version). + /// + /// This method is significantly faster than set_virtual_refs for large + /// numbers of references as it uses Arrow's zero-copy FFI to avoid + /// creating Python objects per chunk. + #[pyo3(signature = (array_path, chunk_grid_shape, locations, offsets, lengths, arr_offset=None, checksum=None, validate_containers=true))] + fn set_virtual_refs_arr( + &self, + py: Python<'_>, + array_path: String, + chunk_grid_shape: Vec, + locations: PyArray, + offsets: PyArray, + lengths: PyArray, + arr_offset: Option>, + checksum: Option, + validate_containers: bool, + ) -> PyIcechunkStoreResult>>> { + let store = Arc::clone(&self.0); + + // Extract Arrow arrays from PyArrow via FFI (zero-copy) + let (locations_arr, _) = locations.into_inner(); + let (offsets_arr, _) = offsets.into_inner(); + let (lengths_arr, _) = lengths.into_inner(); + + // Downcast to concrete types + let locations: Arc = Arc::new( + locations_arr + .as_any() + .downcast_ref::() + .ok_or_else(|| PyValueError::new_err("locations must be a StringArray"))? + .clone(), + ); + let offsets: Arc = Arc::new( + offsets_arr + .as_any() + .downcast_ref::() + .ok_or_else(|| PyValueError::new_err("offsets must be a UInt64Array"))? + .clone(), + ); + let lengths: Arc = Arc::new( + lengths_arr + .as_any() + .downcast_ref::() + .ok_or_else(|| PyValueError::new_err("lengths must be a UInt64Array"))? + .clone(), + ); + + // Convert checksum argument to Checksum type + let checksum: Option = checksum.map(|c| c.into()); + + py.detach(move || { + pyo3_async_runtimes::tokio::get_runtime().block_on(async move { + let array_path = if !array_path.starts_with("/") { + format!("/{array_path}") + } else { + array_path + }; + + let path = Path::try_from(array_path).map_err(|e| { + PyValueError::new_err(format!("Invalid array path: {e}")) + })?; + + let res = store + .set_virtual_refs_from_arrow( + &path, + &chunk_grid_shape, + &locations, + &offsets, + &lengths, + checksum, + arr_offset.as_deref(), + validate_containers, + ) + .await + .map_err(PyIcechunkStoreError::from)?; + + match res { + SetVirtualRefsResult::Done => Ok(None), + SetVirtualRefsResult::FailedRefs(vec) => Python::attach(|py| { + let res = vec + .into_iter() + .map(|ci| PyTuple::new(py, ci.0).map(|tup| tup.unbind())) + .try_collect()?; + Ok(Some(res)) + }), + } + }) + }) + } + + /// Set virtual references using Arrow arrays (async version). + /// + /// This method is significantly faster than set_virtual_refs for large + /// numbers of references as it uses Arrow's zero-copy FFI to avoid + /// creating Python objects per chunk. + #[pyo3(signature = (array_path, chunk_grid_shape, locations, offsets, lengths, arr_offset=None, checksum=None, validate_containers=true))] + fn set_virtual_refs_arr_async<'py>( + &'py self, + py: Python<'py>, + array_path: String, + chunk_grid_shape: Vec, + locations: PyArray, + offsets: PyArray, + lengths: PyArray, + arr_offset: Option>, + checksum: Option, + validate_containers: bool, + ) -> PyResult> { + let store = Arc::clone(&self.0); + + // Extract Arrow arrays from PyArrow via FFI (zero-copy) + let (locations_arr, _) = locations.into_inner(); + let (offsets_arr, _) = offsets.into_inner(); + let (lengths_arr, _) = lengths.into_inner(); + + // Downcast to concrete types + let locations: Arc = Arc::new( + locations_arr + .as_any() + .downcast_ref::() + .ok_or_else(|| PyValueError::new_err("locations must be a StringArray"))? + .clone(), + ); + let offsets: Arc = Arc::new( + offsets_arr + .as_any() + .downcast_ref::() + .ok_or_else(|| PyValueError::new_err("offsets must be a UInt64Array"))? + .clone(), + ); + let lengths: Arc = Arc::new( + lengths_arr + .as_any() + .downcast_ref::() + .ok_or_else(|| PyValueError::new_err("lengths must be a UInt64Array"))? + .clone(), + ); + + // Convert checksum argument to Checksum type + let checksum: Option = checksum.map(|c| c.into()); + + pyo3_async_runtimes::tokio::future_into_py::<_, Option>>>( + py, + async move { + let array_path = if !array_path.starts_with("/") { + format!("/{array_path}") + } else { + array_path + }; + + let path = Path::try_from(array_path).map_err(|e| { + PyValueError::new_err(format!("Invalid array path: {e}")) + })?; + + let res = store + .set_virtual_refs_from_arrow( + &path, + &chunk_grid_shape, + &locations, + &offsets, + &lengths, + checksum, + arr_offset.as_deref(), + validate_containers, + ) + .await + .map_err(PyIcechunkStoreError::from)?; + + match res { + SetVirtualRefsResult::Done => Ok(None), + SetVirtualRefsResult::FailedRefs(vec) => Python::attach(|py| { + let res = vec + .into_iter() + .map(|ci| PyTuple::new(py, ci.0).map(|tup| tup.unbind())) + .try_collect()?; + Ok(Some(res)) + }), + } + }, + ) + } + fn delete<'py>( &'py self, py: Python<'py>, diff --git a/icechunk/Cargo.toml b/icechunk/Cargo.toml index bc2851049..81c0f37ea 100644 --- a/icechunk/Cargo.toml +++ b/icechunk/Cargo.toml @@ -61,6 +61,7 @@ dirs = { version = "6.0.0", optional = true } flexbuffers = "25.12.19" flatbuffers = "25.12.19" urlencoding = "2.1.3" +arrow-array = { version = "57", optional = true } backon = "1.6.0" # reqwest's default-features enables default-tls which ultimately leads to an openssl dependencies @@ -125,6 +126,7 @@ object-store-fs = ["object_store/fs"] redirect = ["dep:reqwest"] logs = ["dep:tracing-subscriber"] cli = ["dep:clap", "dep:anyhow", "dep:dialoguer", "dep:dirs"] +arrow = ["dep:arrow-array"] [[bin]] name = "icechunk" diff --git a/icechunk/src/change_set.rs b/icechunk/src/change_set.rs index 893bb9025..63cee1ad0 100644 --- a/icechunk/src/change_set.rs +++ b/icechunk/src/change_set.rs @@ -457,6 +457,42 @@ impl ChangeSet { Ok(()) } + /// Bulk version of set_chunk_ref - sets multiple chunk refs for the same node. + /// More efficient than calling set_chunk_ref repeatedly as it only does one hash lookup. + pub fn set_chunk_refs( + &mut self, + node_id: NodeId, + chunks: I, + ) -> SessionResult<()> + where + I: IntoIterator)>, + { + let edits = self.edits_mut()?; + + let node_chunks = edits + .set_chunks + .entry(node_id) + .or_default(); + + for (coord, data) in chunks { + let old = node_chunks.insert(coord, data); + + if old.is_none() { + edits.num_chunks += 1; + } + } + + if edits.num_chunks > NUM_CHUNKS_LIMIT && !edits.excessive_num_chunks_warned { + warn!( + "There are more than {NUM_CHUNKS_LIMIT} chunk references being loaded into this commit. This is close to the maximum number of chunk modifications Icechunk supports in a single commit, we recommend to split into smaller commits." + ); + + edits.excessive_num_chunks_warned = true; + } + + Ok(()) + } + pub fn get_chunk_ref( &self, node_id: &NodeId, diff --git a/icechunk/src/session.rs b/icechunk/src/session.rs index 481ee19f6..ea91acb3f 100644 --- a/icechunk/src/session.rs +++ b/icechunk/src/session.rs @@ -683,7 +683,7 @@ impl Session { ) -> SessionResult<()> { let node = self.get_array(node_path).await?; for coord in coords { - self.set_node_chunk_ref(node.clone(), coord, None).await? + self.set_node_chunk_ref(&node, coord, None).await? } Ok(()) } @@ -699,7 +699,7 @@ impl Session { data: Option, ) -> SessionResult<()> { let node_snapshot = self.get_array(&path).await?; - self.set_node_chunk_ref(node_snapshot, coord, data).await + self.set_node_chunk_ref(&node_snapshot, coord, data).await } fn change_set(&self) -> &ChangeSet { @@ -723,17 +723,18 @@ impl Session { self.config.manifest().splitting().get_split_sizes(path, shape, dimension_names) } - // Helper function that accepts a NodeSnapshot instead of a path, - // this lets us do bulk sets (and deletes) without repeatedly grabbing the node. - async fn set_node_chunk_ref( + /// Helper function that accepts a NodeSnapshot instead of a path, + /// this lets us do bulk sets (and deletes) without repeatedly grabbing the node. + #[instrument(skip(self))] + pub async fn set_node_chunk_ref( &mut self, - node: NodeSnapshot, + node: &NodeSnapshot, coord: ChunkIndices, data: Option, ) -> SessionResult<()> { - if let NodeData::Array { shape, .. } = node.node_data { + if let NodeData::Array { ref shape, .. } = node.node_data { if shape.valid_chunk_coord(&coord) { - self.change_set_mut()?.set_chunk_ref(node.id, coord, data)?; + self.change_set_mut()?.set_chunk_ref(node.id.clone(), coord, data)?; Ok(()) } else { Err(SessionErrorKind::InvalidIndex { @@ -751,6 +752,29 @@ impl Session { } } + /// Bulk version - sets multiple chunk refs for a single node. + /// More efficient than calling set_node_chunk_ref repeatedly. + #[instrument(skip(self, chunks))] + pub fn set_node_chunk_refs( + &mut self, + node: &NodeSnapshot, + chunks: I, + ) -> SessionResult<()> + where + I: IntoIterator)>, + { + if let NodeData::Array { .. } = &node.node_data { + self.change_set_mut()?.set_chunk_refs(node.id.clone(), chunks)?; + Ok(()) + } else { + Err(SessionErrorKind::NotAnArray { + node: Box::new(node.clone()), + message: "setting chunk refs".to_string(), + } + .into()) + } + } + #[instrument(skip(self))] pub async fn get_closest_ancestor_node( &self, diff --git a/icechunk/src/store.rs b/icechunk/src/store.rs index a2ae97e26..bbe87bd05 100644 --- a/icechunk/src/store.rs +++ b/icechunk/src/store.rs @@ -30,7 +30,7 @@ use crate::{ error::ICError, format::{ ByteRange, ChunkIndices, ChunkOffset, Path, PathError, - manifest::{ChunkPayload, VirtualChunkRef}, + manifest::{Checksum, ChunkPayload, VirtualChunkLocation, VirtualChunkRef}, snapshot::{ArrayShape, DimensionName, NodeData, NodeSnapshot, NodeType}, }, refs::{RefError, RefErrorKind}, @@ -423,22 +423,27 @@ impl Store { } let mut session = self.session.write().await; + let node = session.get_array(array_path).await?; + + // Separate valid refs from failed ones let mut failed = Vec::new(); - for (index, reference) in references.into_iter() { - if validate_container - && session.matching_container(&reference.location).is_none() - { - failed.push(index); - } else { - session - .set_chunk_ref( - array_path.clone(), - index, - Some(ChunkPayload::Virtual(reference)), - ) - .await?; - } - } + let valid_refs: Vec<_> = references + .into_iter() + .filter_map(|(index, reference)| { + if validate_container + && session.matching_container(&reference.location).is_none() + { + failed.push(index); + None + } else { + Some((index, Some(ChunkPayload::Virtual(reference)))) + } + }) + .collect(); + + // Use bulk method - one hash lookup for all refs + session.set_node_chunk_refs(&node, valid_refs)?; + if failed.is_empty() { Ok(SetVirtualRefsResult::Done) } else { @@ -446,6 +451,88 @@ impl Store { } } + /// Set virtual references from Arrow arrays. + /// + /// This is more efficient than `set_virtual_refs` when called from Python + /// as it avoids creating millions of intermediate Python objects. + /// + /// # Arguments + /// * `array_path` - Path to the array in the store + /// * `chunk_grid_shape` - Shape of the chunk grid (product must equal array lengths) + /// * `locations` - Arrow StringArray of URLs to external files + /// * `offsets` - Arrow UInt64Array of byte offsets + /// * `lengths` - Arrow UInt64Array of byte lengths + /// * `checksum` - Optional checksum applied to all chunks (e.g., LastModified timestamp) + /// * `arr_offset` - Optional offset to add to computed chunk indices (for append operations) + /// * `validate_container` - If true, validate locations match registered containers + #[cfg(feature = "arrow")] + #[instrument(skip(self, locations, offsets, lengths))] + pub async fn set_virtual_refs_from_arrow( + &self, + array_path: &Path, + chunk_grid_shape: &[u32], + locations: &arrow_array::StringArray, + offsets: &arrow_array::UInt64Array, + lengths: &arrow_array::UInt64Array, + checksum: Option, + arr_offset: Option<&[u32]>, + validate_container: bool, + ) -> StoreResult { + use arrow_array::Array; + + let n_chunks = locations.len(); + + // Validate array lengths match + if offsets.len() != n_chunks || lengths.len() != n_chunks { + return Err(StoreErrorKind::Other( + "Arrow array lengths must match".to_string(), + ) + .into()); + } + + // Validate chunk_grid_shape product equals n_chunks + let expected: usize = chunk_grid_shape.iter().map(|&x| x as usize).product(); + if expected != n_chunks { + return Err(StoreErrorKind::Other(format!( + "chunk_grid_shape product ({}) != array length ({})", + expected, n_chunks + )) + .into()); + } + + // Validate arr_offset length if provided + if let Some(offset) = arr_offset { + if offset.len() != chunk_grid_shape.len() { + return Err(StoreErrorKind::Other(format!( + "arr_offset length ({}) != chunk_grid_shape length ({})", + offset.len(), + chunk_grid_shape.len() + )) + .into()); + } + } + + // Build refs by iterating Arrow arrays, skipping null entries (missing chunks) + let refs_iter: Vec<(ChunkIndices, VirtualChunkRef)> = (0..n_chunks) + .filter(|&i| !locations.is_null(i)) + .map(|i| { + let indices = flat_to_nd_indices(i, chunk_grid_shape, arr_offset); + let location = VirtualChunkLocation::from_url(locations.value(i)) + .map_err(|e| StoreErrorKind::Other(e.to_string()))?; + let vref = VirtualChunkRef { + location, + offset: offsets.value(i), + length: lengths.value(i), + checksum: checksum.clone(), + }; + Ok((ChunkIndices(indices), vref)) + }) + .collect::, StoreError>>()?; + + // Delegate to existing method + self.set_virtual_refs(array_path, validate_container, refs_iter).await + } + #[instrument(skip(self))] pub async fn delete_dir(&self, prefix: &str) -> StoreResult<()> { if self.read_only().await { @@ -846,6 +933,27 @@ impl Store { } } +/// Convert flat index to N-dimensional indices (C-order/row-major). +/// +/// Used by `set_virtual_refs_from_arrow` to compute chunk coordinates +/// from the flat position in the Arrow arrays. +/// +/// If `offset` is provided, it is added element-wise to the computed indices. +#[cfg(feature = "arrow")] +fn flat_to_nd_indices(flat: usize, shape: &[u32], offset: Option<&[u32]>) -> Vec { + // TODO: check that this vibe-coded function makes any sense at all... + let total: usize = shape.iter().map(|&d| d as usize).product(); + shape + .iter() + .enumerate() + .scan(total, |stride, (i, &dim)| { + *stride /= dim as usize; + let idx = ((flat / *stride) % dim as usize) as u32; + Some(idx + offset.map_or(0, |o| o[i])) + }) + .collect() +} + async fn set_array_meta( path: Path, user_data: Bytes, @@ -2460,4 +2568,70 @@ mod tests { Bytes::copy_from_slice(br#"{"zarr_format":3,"node_type":"group"}"#) ); } + + #[cfg(feature = "arrow")] + #[tokio::test] + async fn test_set_virtual_refs_from_arrow_skips_nulls() { + use arrow_array::{StringArray, UInt64Array}; + + let repo = create_memory_store_repository().await; + let session = Arc::new(RwLock::new(repo.writable_session("main").await.unwrap())); + let store = Store::from_session(Arc::clone(&session)).await; + + // Create a group and array + store + .set( + "zarr.json", + Bytes::copy_from_slice(br#"{"zarr_format":3,"node_type":"group"}"#), + ) + .await + .unwrap(); + + store + .set( + "array/zarr.json", + Bytes::copy_from_slice( + br#"{"zarr_format":3,"node_type":"array","shape":[3],"data_type":"int32","chunk_grid":{"name":"regular","configuration":{"chunk_shape":[1]}},"chunk_key_encoding":{"name":"default","configuration":{"separator":"/"}},"fill_value":0,"codecs":[{"name":"bytes","configuration":{"endian":"little"}}]}"#, + ), + ) + .await + .unwrap(); + + // Create Arrow arrays with one null entry (should be skipped) + let locations = StringArray::from(vec![Some("s3://bucket/file1.dat"), None, Some("s3://bucket/file3.dat")]); + let offsets = UInt64Array::from(vec![Some(0), None, Some(200)]); + let lengths = UInt64Array::from(vec![Some(50), None, Some(50)]); + + let result = store + .set_virtual_refs_from_arrow( + &"/array".try_into().unwrap(), + &[3], + &locations, + &offsets, + &lengths, + None, + None, + false, + ) + .await + .unwrap(); + + // Should succeed - null entry at index 1 should be skipped + assert!(matches!(result, SetVirtualRefsResult::Done)); + + // Verify only 2 chunks were written (indices 0 and 2, not 1) + let keys: Vec = store + .list_prefix("array") + .await + .unwrap() + .try_collect() + .await + .unwrap(); + // Should have zarr.json + 2 chunks (c/0 and c/2) + assert_eq!(keys.len(), 3); + assert!(keys.contains(&"array/zarr.json".to_string())); + assert!(keys.contains(&"array/c/0".to_string())); + assert!(keys.contains(&"array/c/2".to_string())); + assert!(!keys.contains(&"array/c/1".to_string())); + } } diff --git a/icechunk/tests/test_virtual_refs.rs b/icechunk/tests/test_virtual_refs.rs index 8f7181485..caf779d45 100644 --- a/icechunk/tests/test_virtual_refs.rs +++ b/icechunk/tests/test_virtual_refs.rs @@ -1120,6 +1120,82 @@ async fn test_zarr_store_with_multiple_virtual_chunk_containers( Ok(()) } +#[cfg(feature = "arrow")] +#[tokio_test] +async fn test_set_virtual_refs_from_arrow() -> Result<(), Box> { + use arrow_array::{StringArray, UInt64Array}; + + let chunk_dir = TempDir::new()?; + let chunk_1 = chunk_dir.path().join("chunk-1").to_str().unwrap().to_owned(); + let chunk_2 = chunk_dir.path().join("chunk-2").to_str().unwrap().to_owned(); + let chunk_3 = chunk_dir.path().join("chunk-3").to_str().unwrap().to_owned(); + let chunk_4 = chunk_dir.path().join("chunk-4").to_str().unwrap().to_owned(); + + let bytes1 = Bytes::copy_from_slice(b"first"); + let bytes2 = Bytes::copy_from_slice(b"second"); + let bytes3 = Bytes::copy_from_slice(b"third!"); + let bytes4 = Bytes::copy_from_slice(b"fourth"); + let chunks = [ + (chunk_1.clone(), bytes1.clone()), + (chunk_2.clone(), bytes2.clone()), + (chunk_3.clone(), bytes3.clone()), + (chunk_4.clone(), bytes4.clone()), + ]; + write_chunks_to_local_fs(chunks.iter().cloned()).await; + + let repo_dir = TempDir::new()?; + let repo = create_local_repository(repo_dir.path(), Some(chunk_dir.path())).await; + let session = repo.writable_session("main").await.unwrap(); + let store = Store::from_session(Arc::new(RwLock::new(session))).await; + + // Set up array metadata + store + .set( + "zarr.json", + Bytes::copy_from_slice(br#"{"zarr_format":3, "node_type":"group"}"#), + ) + .await?; + let zarr_meta = Bytes::copy_from_slice(br#"{"zarr_format":3,"node_type":"array","attributes":{},"shape":[2,2],"data_type":"int32","chunk_grid":{"name":"regular","configuration":{"chunk_shape":[1,1]}},"chunk_key_encoding":{"name":"default","configuration":{"separator":"/"}},"fill_value":0,"codecs":[{"name":"bytes","configuration":{"endian":"little"}}],"storage_transformers":[],"dimension_names":["x","y"]}"#); + store.set("array/zarr.json", zarr_meta).await?; + + // Create Arrow arrays for 4 chunks in a 2x2 grid (C-order: [0,0], [0,1], [1,0], [1,1]) + let locations = StringArray::from(vec![ + format!("file://{}", chunk_1), + format!("file://{}", chunk_2), + format!("file://{}", chunk_3), + format!("file://{}", chunk_4), + ]); + let offsets = UInt64Array::from(vec![0, 0, 0, 0]); + let lengths = UInt64Array::from(vec![5, 6, 6, 6]); + + // Call set_virtual_refs_from_arrow + let array_path: Path = "/array".try_into().unwrap(); + let chunk_grid_shape = vec![2u32, 2u32]; + let result = store + .set_virtual_refs_from_arrow( + &array_path, + &chunk_grid_shape, + &locations, + &offsets, + &lengths, + None, // checksum + None, // arr_offset + false, // don't validate containers + ) + .await?; + + // Check result is success + assert!(matches!(result, icechunk::store::SetVirtualRefsResult::Done)); + + // Verify we can read the chunks back + assert_eq!(store.get("array/c/0/0", &ByteRange::ALL).await?, bytes1); + assert_eq!(store.get("array/c/0/1", &ByteRange::ALL).await?, bytes2); + assert_eq!(store.get("array/c/1/0", &ByteRange::ALL).await?, bytes3); + assert_eq!(store.get("array/c/1/1", &ByteRange::ALL).await?, bytes4); + + Ok(()) +} + #[tokio_test] #[apply(spec_version_cases)] async fn test_virtual_refs_with_vcc_relative_urls(