From 59440d94249e43925eb1b4e3998ff8fe29b4eacd Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Mon, 11 May 2026 20:42:49 +0300 Subject: [PATCH 1/7] Add PHP SDK coverage for Apache Iggy The PHP extension client needs to build independently from the root Rust workspace while still testing against the in-tree Rust SDK. This adds the PHP binding package, Dockerized integration test path, and CI detection so PHP-only changes exercise the right checks. Constraint: Foreign SDK crates are kept outside the root workspace like the existing Python and C++ SDKs Constraint: PHP extension builds require php-config, cargo-php, and libclang in containerized CI Rejected: Leave PHP tests manual only | PHP-only PRs would not run SDK-specific validation Confidence: medium Scope-risk: moderate Directive: Keep foreign/php excluded from the root Cargo workspace unless the extension build is intentionally made workspace-compatible Tested: cargo fmt --manifest-path foreign/php/Cargo.toml --check; composer validate --working-dir foreign/php --strict; PHP syntax lint for tests; cargo metadata --manifest-path foreign/php/Cargo.toml; docker compose config; docker compose build php-tests; PHP integration smoke against apache/iggy:latest with 23 passed, 3 skipped, 0 failed Not-tested: Full docker compose test with source-built Iggy server after php-tests image build --- .github/config/components.yml | 9 + .github/workflows/_detect.yml | 11 +- .github/workflows/_test.yml | 17 + .github/workflows/pre-merge.yml | 15 +- Cargo.toml | 2 +- foreign/php/.cargo/config.toml | 22 + foreign/php/.gitignore | 4 + foreign/php/Cargo.lock | 5479 ++++++++++++++++++++++++ foreign/php/Cargo.toml | 40 + foreign/php/Dockerfile.test | 59 + foreign/php/LICENSE | 201 + foreign/php/NOTICE | 12 + foreign/php/README.md | 202 + foreign/php/composer.json | 13 + foreign/php/composer.lock | 172 + foreign/php/docker-compose.test.yml | 66 + foreign/php/scripts/test.sh | 38 + foreign/php/src/async_client.rs | 376 ++ foreign/php/src/async_consumer.rs | 166 + foreign/php/src/client.rs | 350 ++ foreign/php/src/consumer.rs | 280 ++ foreign/php/src/identifier.rs | 59 + foreign/php/src/iterator.rs | 65 + foreign/php/src/lib.rs | 60 + foreign/php/src/receive_message.rs | 148 + foreign/php/src/send_message.rs | 84 + foreign/php/src/stream.rs | 56 + foreign/php/src/topic.rs | 54 + foreign/php/tests/IggyAsyncSdkTest.php | 195 + foreign/php/tests/IggySdkTest.php | 364 ++ foreign/php/tests/TlsTest.php | 82 + foreign/php/tests/bootstrap.php | 198 + foreign/php/tests/run.php | 81 + 33 files changed, 8977 insertions(+), 3 deletions(-) create mode 100644 foreign/php/.cargo/config.toml create mode 100644 foreign/php/.gitignore create mode 100644 foreign/php/Cargo.lock create mode 100644 foreign/php/Cargo.toml create mode 100644 foreign/php/Dockerfile.test create mode 100644 foreign/php/LICENSE create mode 100644 foreign/php/NOTICE create mode 100644 foreign/php/README.md create mode 100644 foreign/php/composer.json create mode 100644 foreign/php/composer.lock create mode 100644 foreign/php/docker-compose.test.yml create mode 100755 foreign/php/scripts/test.sh create mode 100644 foreign/php/src/async_client.rs create mode 100644 foreign/php/src/async_consumer.rs create mode 100644 foreign/php/src/client.rs create mode 100644 foreign/php/src/consumer.rs create mode 100644 foreign/php/src/identifier.rs create mode 100644 foreign/php/src/iterator.rs create mode 100644 foreign/php/src/lib.rs create mode 100644 foreign/php/src/receive_message.rs create mode 100644 foreign/php/src/send_message.rs create mode 100644 foreign/php/src/stream.rs create mode 100644 foreign/php/src/topic.rs create mode 100644 foreign/php/tests/IggyAsyncSdkTest.php create mode 100644 foreign/php/tests/IggySdkTest.php create mode 100644 foreign/php/tests/TlsTest.php create mode 100644 foreign/php/tests/bootstrap.php create mode 100644 foreign/php/tests/run.php diff --git a/.github/config/components.yml b/.github/config/components.yml index e7b6dbbbc5..4b709f0a6f 100644 --- a/.github/config/components.yml +++ b/.github/config/components.yml @@ -200,6 +200,15 @@ components: - "foreign/python/**" tasks: ["lint", "test", "build"] + sdk-php: + depends_on: + - "rust-sdk" # PHP SDK wraps the Rust SDK + - "rust-server" # For integration tests + - "ci-infrastructure" # CI changes trigger full regression + paths: + - "foreign/php/**" + tasks: ["build", "test"] + sdk-node: depends_on: - "rust-sdk" # Node SDK depends on core SDK diff --git a/.github/workflows/_detect.yml b/.github/workflows/_detect.yml index ff11fe9036..e35eaadfb2 100644 --- a/.github/workflows/_detect.yml +++ b/.github/workflows/_detect.yml @@ -26,6 +26,9 @@ on: python_matrix: description: "Matrix for Python SDK" value: ${{ jobs.detect.outputs.python_matrix }} + php_matrix: + description: "Matrix for PHP SDK" + value: ${{ jobs.detect.outputs.php_matrix }} node_matrix: description: "Matrix for Node SDK" value: ${{ jobs.detect.outputs.node_matrix }} @@ -57,6 +60,7 @@ jobs: outputs: rust_matrix: ${{ steps.mk.outputs.rust_matrix }} python_matrix: ${{ steps.mk.outputs.python_matrix }} + php_matrix: ${{ steps.mk.outputs.php_matrix }} node_matrix: ${{ steps.mk.outputs.node_matrix }} go_matrix: ${{ steps.mk.outputs.go_matrix }} java_matrix: ${{ steps.mk.outputs.java_matrix }} @@ -227,7 +231,7 @@ jobs: console.log(`Total files changed: ${files.length}`); } - const groups = { rust:[], python:[], node:[], go:[], java:[], csharp:[], cpp:[], bdd:[], examples:[], other:[] }; + const groups = { rust:[], python:[], php:[], node:[], go:[], java:[], csharp:[], cpp:[], bdd:[], examples:[], other:[] }; // Process affected components and generate tasks console.log(''); @@ -250,6 +254,7 @@ jobs: if (name === 'rust') groups.rust.push(...entries); else if (name === 'sdk-python') groups.python.push(...entries); + else if (name === 'sdk-php') groups.php.push(...entries); else if (name === 'sdk-node') groups.node.push(...entries); else if (name === 'sdk-go') groups.go.push(...entries); else if (name === 'sdk-java') groups.java.push(...entries); @@ -296,6 +301,7 @@ jobs: // Clear existing groups to avoid duplicates - we'll run everything anyway groups.rust = []; groups.python = []; + groups.php = []; groups.node = []; groups.go = []; groups.java = []; @@ -310,6 +316,7 @@ jobs: const entries = cfg.tasks.map(task => ({ component: name, task })); if (name === 'rust') groups.rust.push(...entries); else if (name === 'sdk-python') groups.python.push(...entries); + else if (name === 'sdk-php') groups.php.push(...entries); else if (name === 'sdk-node') groups.node.push(...entries); else if (name === 'sdk-go') groups.go.push(...entries); else if (name === 'sdk-java') groups.java.push(...entries); @@ -346,6 +353,7 @@ jobs: const jobSummary = [ { name: 'Rust', tasks: groups.rust }, { name: 'Python SDK', tasks: groups.python }, + { name: 'PHP SDK', tasks: groups.php }, { name: 'Node SDK', tasks: groups.node }, { name: 'Go SDK', tasks: groups.go }, { name: 'Java SDK', tasks: groups.java }, @@ -378,6 +386,7 @@ jobs: setOutput('rust_matrix', JSON.stringify(matrix(groups.rust))); setOutput('python_matrix', JSON.stringify(matrix(groups.python))); + setOutput('php_matrix', JSON.stringify(matrix(groups.php))); setOutput('node_matrix', JSON.stringify(matrix(groups.node))); setOutput('go_matrix', JSON.stringify(matrix(groups.go))); setOutput('java_matrix', JSON.stringify(matrix(groups.java))); diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index dc405f2795..3215ee9936 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -97,6 +97,23 @@ jobs: verbose: true override_pr: ${{ github.event.pull_request.number }} + # PHP SDK + - name: Set up Docker Buildx for PHP + if: inputs.component == 'sdk-php' + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 + + - name: Run PHP SDK task + if: inputs.component == 'sdk-php' + run: | + if [ "${{ inputs.task }}" = "build" ]; then + docker compose -f foreign/php/docker-compose.test.yml build php-tests + elif [ "${{ inputs.task }}" = "test" ]; then + docker compose -f foreign/php/docker-compose.test.yml up --build --abort-on-container-exit --exit-code-from php-tests + else + echo "Unknown PHP SDK task: ${{ inputs.task }}" + exit 1 + fi + # Node SDK - name: Run Node SDK task if: inputs.component == 'sdk-node' diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml index 0cac3a2345..25a88bcbb8 100644 --- a/.github/workflows/pre-merge.yml +++ b/.github/workflows/pre-merge.yml @@ -78,6 +78,19 @@ jobs: secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + # PHP SDK + test-php: + name: PHP • ${{ matrix.task }} + needs: detect + if: ${{ fromJson(needs.detect.outputs.php_matrix).include[0].component != 'noop' }} + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.detect.outputs.php_matrix) }} + uses: ./.github/workflows/_test.yml + with: + component: ${{ matrix.component }} + task: ${{ matrix.task }} + # Node SDK test-node: name: Node • ${{ matrix.task }} @@ -194,7 +207,7 @@ jobs: status: name: CI Status runs-on: ubuntu-latest - needs: [common, detect, test-rust, test-python, test-node, test-go, test-java, test-csharp, test-cpp, test-bdd, test-examples, test-other] + needs: [common, detect, test-rust, test-python, test-php, test-node, test-go, test-java, test-csharp, test-cpp, test-bdd, test-examples, test-other] if: always() steps: - name: Get job execution times diff --git a/Cargo.toml b/Cargo.toml index 949a498f2a..da112fc385 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ members = [ "core/tools", "examples/rust", ] -exclude = ["foreign/cpp", "foreign/python"] +exclude = ["foreign/cpp", "foreign/php", "foreign/python"] resolver = "2" [workspace.dependencies] diff --git a/foreign/php/.cargo/config.toml b/foreign/php/.cargo/config.toml new file mode 100644 index 0000000000..652a1ff9c0 --- /dev/null +++ b/foreign/php/.cargo/config.toml @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +[target.aarch64-apple-darwin] +rustflags = ["-C", "link-arg=-Wl,-undefined,dynamic_lookup"] + +[target.x86_64-apple-darwin] +rustflags = ["-C", "link-arg=-Wl,-undefined,dynamic_lookup"] diff --git a/foreign/php/.gitignore b/foreign/php/.gitignore new file mode 100644 index 0000000000..9b5cec80ec --- /dev/null +++ b/foreign/php/.gitignore @@ -0,0 +1,4 @@ +/target +.omx/ +/vendor +/test-results diff --git a/foreign/php/Cargo.lock b/foreign/php/Cargo.lock new file mode 100644 index 0000000000..79c9126bb7 --- /dev/null +++ b/foreign/php/Cargo.lock @@ -0,0 +1,5479 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common 0.1.7", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bd29a732b644c0431c6140f370d097879203d79b80c94a6747ba0872adaef8" +dependencies = [ + "cipher 0.5.1", + "cpubits", + "cpufeatures 0.3.0", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes 0.8.4", + "cipher 0.4.4", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-dropper" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d901072ae4dcdca2201b98beb02d31fb4b6b2472fbd0e870b12ec15b8b35b2d2" +dependencies = [ + "async-dropper-derive", + "async-dropper-simple", + "async-trait", + "futures", + "tokio", +] + +[[package]] +name = "async-dropper-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35cf17a37761f1c88b8e770b5956820fe84c12854165b6f930c604ea186e47e" +dependencies = [ + "async-trait", + "proc-macro2", + "quote", + "syn 2.0.117", + "tokio", +] + +[[package]] +name = "async-dropper-simple" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c4748dfe8cd3d625ec68fc424fa80c134319881185866f9e173af9e5d8add8" +dependencies = [ + "async-scoped", + "async-trait", + "futures", + "rustc_version", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-scoped" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4042078ea593edffc452eef14e99fdb2b120caa4ad9618bcdeabc4a023b98740" +dependencies = [ + "futures", + "pin-project", + "tokio", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", + "zeroize", +] + +[[package]] +name = "bon" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" +dependencies = [ + "darling 0.23.0", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byte-unit" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" +dependencies = [ + "rust_decimal", + "schemars 1.2.1", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "bzip2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" +dependencies = [ + "libbz2-rs-sys", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cc" +version = "1.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout 0.1.4", +] + +[[package]] +name = "cipher" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" +dependencies = [ + "crypto-common 0.2.1", + "inout 0.2.2", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "comfy-table" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" +dependencies = [ + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "compio" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b84ee96a86948d04388f3a0b8c36b9f0a6b40b3528ac0d65737e53632fb37fe" +dependencies = [ + "compio-buf", + "compio-driver", + "compio-fs", + "compio-io", + "compio-log", + "compio-macros", + "compio-net", + "compio-quic", + "compio-runtime", + "compio-tls", + "compio-ws", +] + +[[package]] +name = "compio-buf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00d719dbd8c602ab0d25d219cbc6b517008858de7a8d6c51b4dc95aefff4dce" +dependencies = [ + "arrayvec", + "bytes", + "libc", +] + +[[package]] +name = "compio-driver" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d42d98dc890ee4db00c1e68a723391711aab6d67085880d716b72830f7c715" +dependencies = [ + "cfg-if", + "cfg_aliases", + "compio-buf", + "compio-log", + "crossbeam-queue", + "flume", + "futures-util", + "io-uring", + "io_uring_buf_ring", + "libc", + "once_cell", + "paste", + "pin-project-lite", + "polling", + "slab", + "smallvec", + "socket2", + "synchrony", + "thin-cell", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-fs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ee36e1acf2cec4835efe9a986c012b2462c5ef53580e4ee84ae6d5a3d8e3b3" +dependencies = [ + "cfg-if", + "cfg_aliases", + "compio-buf", + "compio-driver", + "compio-io", + "compio-runtime", + "libc", + "os_pipe", + "pin-project-lite", + "widestring", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-io" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637522f28a64fd5f7dcceaa4ddef13fa8d8020025e8c993f7a069e237835580e" +dependencies = [ + "compio-buf", + "futures-util", + "paste", + "synchrony", +] + +[[package]] +name = "compio-log" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4e560213c1996b618da369b7c9109564b41af9033802ae534465c4ee4e132f" +dependencies = [ + "tracing", +] + +[[package]] +name = "compio-macros" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05ed201484967dc70de77a8f7a02b29aaa8e6c81cbea2e75492ee0c8d97766b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "compio-net" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "becd7d40522c885113752a3640cba9f9d347f205b646bb3f8ff3967173a228f2" +dependencies = [ + "cfg-if", + "compio-buf", + "compio-driver", + "compio-io", + "compio-runtime", + "either", + "libc", + "once_cell", + "socket2", + "widestring", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-quic" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9efdad81b920108b9de57148e1b9d73dc408b6d06a59ee64836dde651cf026" +dependencies = [ + "cfg_aliases", + "compio-buf", + "compio-io", + "compio-log", + "compio-net", + "compio-runtime", + "flume", + "futures-util", + "libc", + "quinn-proto", + "rustc-hash", + "rustls", + "synchrony", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-runtime" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c1c71f011bdd9c8f30e97d877b606505ee6d241c7782cfaed172f66acbd9cd" +dependencies = [ + "async-task", + "cfg-if", + "compio-buf", + "compio-driver", + "compio-log", + "core_affinity", + "crossbeam-queue", + "futures-util", + "libc", + "once_cell", + "pin-project-lite", + "scoped-tls", + "slab", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "compio-tls" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a7056da226af42cda4c83b00a021cce3e1ee5f4cffc8a0ff8801381e618cf1c" +dependencies = [ + "compio-buf", + "compio-io", + "futures-rustls", + "futures-util", + "rustls", +] + +[[package]] +name = "compio-ws" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d45f47c6e64babcaa6b8df1dffced56012e60e58401255e679f428ddbe9fb6" +dependencies = [ + "compio-buf", + "compio-io", + "compio-log", + "compio-net", + "compio-tls", + "tungstenite 0.28.0", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_affinity" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a034b3a7b624016c6e13f5df875747cc25f884156aad2abd12b6c46797971342" +dependencies = [ + "libc", + "num_cpus", + "winapi", +] + +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "deflate64" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case 0.10.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "const-oid", + "crypto-common 0.2.1", + "ctutils", + "zeroize", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "enumset" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f96a4a12fe60ac746ae295a1a4ecb5bb02debc20856506c8635288065f142de" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "err_trail" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0364ccf1c57e1e4e22f47418b0197163424aa97037b07fc3626a855d94549503" +dependencies = [ + "tracing", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "ext-php-rs" +version = "0.15.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ba219f32e80a5ab8b2562b873f15aeac8028aff1fb1a898409b2e251bfe59d" +dependencies = [ + "anyhow", + "bitflags", + "cc", + "cfg-if", + "ext-php-rs-bindgen", + "ext-php-rs-build", + "ext-php-rs-derive", + "inventory", + "native-tls", + "once_cell", + "parking_lot", + "skeptic", + "ureq", + "zip", +] + +[[package]] +name = "ext-php-rs-bindgen" +version = "0.72.1-extphprs.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4795dd0976bd7d7d321c49e88e836f8e5b5b2b481e089067e303f2945617458a" +dependencies = [ + "bitflags", + "cexpr", + "ext-php-rs-clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.117", +] + +[[package]] +name = "ext-php-rs-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561bce8a6312a6182c078cd987d8d9cb6bf9292a35817cfd009ea0bffa794f5f" +dependencies = [ + "anyhow", +] + +[[package]] +name = "ext-php-rs-clang-sys" +version = "1.8.1-extphprs.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa1ad6e482017d457d57d73691f8bed148a8a6198babe90830310c3308480a61" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "ext-php-rs-derive" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6cb94d5f4c1e9758b6b936ad306dea36a034c125334d9a438fe966a5d596a85" +dependencies = [ + "convert_case 0.11.0", + "darling 0.23.0", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ext-trait" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5" +dependencies = [ + "ext-trait-proc_macros", +] + +[[package]] +name = "ext-trait-proc_macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "extension-traits" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537" +dependencies = [ + "ext-trait", +] + +[[package]] +name = "fastbloom" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" +dependencies = [ + "getrandom 0.3.4", + "libm", + "rand 0.9.4", + "siphasher", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "fastrand", + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls", + "rustls-pki-types", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasip2", + "wasip3", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "human-repr" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58b778a5761513caf593693f8951c97a5b610841e754788400f32102eefdff1" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "iggy" +version = "0.10.0" +dependencies = [ + "async-broadcast", + "async-dropper", + "async-trait", + "bon", + "bytes", + "dashmap", + "flume", + "futures", + "futures-util", + "iggy_common", + "quinn", + "reqwest", + "reqwest-middleware", + "reqwest-retry", + "reqwest-tracing", + "rustls", + "secrecy", + "serde", + "tokio", + "tokio-rustls", + "tokio-tungstenite", + "tracing", + "trait-variant", + "webpki-roots 1.0.7", +] + +[[package]] +name = "iggy-php" +version = "0.1.0" +dependencies = [ + "bytes", + "ext-php-rs", + "futures", + "iggy", + "php-tokio", + "tokio", +] + +[[package]] +name = "iggy_binary_protocol" +version = "0.10.0" +dependencies = [ + "aligned-vec", + "bytemuck", + "bytes", + "compio-buf", + "enumset", + "secrecy", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "iggy_common" +version = "0.10.0" +dependencies = [ + "aes-gcm", + "aligned-vec", + "async-broadcast", + "async-trait", + "base64", + "blake3", + "bon", + "byte-unit", + "bytemuck", + "bytes", + "chrono", + "clap", + "comfy-table", + "compio", + "crossbeam", + "derive_more", + "err_trail", + "human-repr", + "humantime", + "iggy_binary_protocol", + "lending-iterator", + "moka", + "nix", + "once_cell", + "papaya", + "rcgen", + "ring", + "rustls", + "secrecy", + "serde", + "serde_json", + "serde_with", + "strum", + "thiserror 2.0.18", + "tokio", + "tracing", + "tungstenite 0.29.0", + "twox-hash", + "ulid", + "uuid", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "inventory" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" +dependencies = [ + "rustversion", +] + +[[package]] +name = "io-uring" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d09b98f7eace8982db770e4408e7470b028ce513ac28fecdc6bf4c30fe92b62" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "io_uring_buf_ring" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1838759bb8c2f24cf05a35429d83145c4aa6af43f8ad38477295e12a7320a80e" +dependencies = [ + "bytes", + "io-uring", + "rustix", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "lending-iterator" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc07588c853b50689205fb5c00498aa681d89828e0ce8cbd965ebc7a5d8ae260" +dependencies = [ + "extension-traits", + "lending-iterator-proc_macros", + "macro_rules_attribute", + "never-say-never", + "nougat", + "polonius-the-crab", +] + +[[package]] +name = "lending-iterator-proc_macros" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5445dd1c0deb1e97b8a16561d17fc686ca83e8411128fb036e9668a72d51b1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "libbz2-rs-sys" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a6a8c165077efc8f3a971534c50ea6a1a18b329ef4a66e897a7e3a1494565f" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "pin-utils", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "lzma-rust2" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47bb1e988e6fb779cf720ad431242d3f03167c1b3f2b1aae7f1a94b2495b36ae" +dependencies = [ + "sha2", +] + +[[package]] +name = "macro_rules_attribute" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862" +dependencies = [ + "macro_rules_attribute-proc_macro", + "paste", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f926ade0c4e170215ae43342bf13b9310a437609c81f29f86c5df6657582ef9" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "moka" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "never-say-never" +version = "6.6.666" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5a574dadd7941adeaa71823ecba5e28331b8313fb2e1c6a5c7e5981ea53ad6" + +[[package]] +name = "nix" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nougat" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b57b9ced431322f054fc673f1d3c7fa52d80efd9df74ad2fc759f044742510" +dependencies = [ + "macro_rules_attribute", + "nougat-proc_macros", +] + +[[package]] +name = "nougat-proc_macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84f77a45e99a2f9b492695d99e1c23844619caa5f3e57647cffacad773ca257" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-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-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0b434746ee2832f4f0baf10137e1cabb18cbe6912c69e2e33263c45250f542" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "158fe5b292746440aa6e7a7e690e55aeb72d41505e2804c23c6973ad0e9c9781" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "papaya" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "997ee03cd38c01469a7046643714f0ad28880bcb9e6679ff0666e24817ca19b7" +dependencies = [ + "equivalent", + "seize", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" +dependencies = [ + "digest 0.11.3", + "hmac", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "php-tokio" +version = "0.1.7" +source = "git+https://github.com/danog/php-tokio.git?tag=0.1.11#006da31b54346a5f485c914f513871c30482cf2a" +dependencies = [ + "ext-php-rs", + "lazy_static", + "libc", + "php-tokio-derive", + "tokio", + "tokio-pipe", +] + +[[package]] +name = "php-tokio-derive" +version = "0.2.0" +source = "git+https://github.com/danog/php-tokio.git?tag=0.1.11#006da31b54346a5f485c914f513871c30482cf2a" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf0d9e68100b3a7989b4901972f265cd542e560a3a8a724e1e20322f4d06ce9" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a990e22f43e84855daf260dded30524ef4a9021cc7541c26540500a50b624389" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "polonius-the-crab" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a69ee997a6282f8462abf1e0d8c38c965e968799e912b3bed8c9e8a28c2f9f" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppmd-rust" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efca4c95a19a79d1c98f791f10aebd5c1363b473244630bb7dbde1dc98455a24" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "aws-lc-rs", + "bytes", + "fastbloom", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier 0.6.2", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rcgen" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10b99e0098aa4082912d4c649628623db6aba77335e4f4569ff5083a6448b32e" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "x509-parser", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier 0.7.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "reqwest-middleware" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199dda04a536b532d0cc04d7979e39b1c763ea749bf91507017069c00b96056f" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "thiserror 2.0.18", + "tower-service", +] + +[[package]] +name = "reqwest-retry" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2412db2af7d2268e7a5406be0431f37d9eb67ff390f35b395716f5f06c2eaa" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "getrandom 0.2.17", + "http", + "hyper", + "reqwest", + "reqwest-middleware", + "retry-policies", + "thiserror 2.0.18", + "tokio", + "tracing", + "wasmtimer", +] + +[[package]] +name = "reqwest-tracing" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5c1a1510677d43dce9e9c0c07fc5db8772c0e5a43e4f9cef75a11affa05a578" +dependencies = [ + "anyhow", + "async-trait", + "getrandom 0.2.17", + "http", + "matchit", + "reqwest", + "reqwest-middleware", + "tracing", +] + +[[package]] +name = "retry-policies" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc05fbf560421a0357a750cbe78c7ca19d4923918490daabba313d5dbc871e47" +dependencies = [ + "rand 0.10.1", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c5108e3d4d903e21aac27f12ba5377b6b34f9f44b325e4894c7924169d06995" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.6", + "rkyv", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni 0.21.1", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni 0.22.4", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "seize" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +dependencies = [ + "base64", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synchrony" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416090a4d8f6358526df5f9f65dfe28750b8b7bfd1fd8a5620f483fc4a75722c" +dependencies = [ + "futures-util", + "loom", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thin-cell" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4164c6c316ba9733b0ab021e7f9852c788a4b991b49c25820f1be48e1d41345b" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "js-sys", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-pipe" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f213a84bffbd61b8fa0ba8a044b4bbe35d471d0b518867181e82bd5c15542784" +dependencies = [ + "libc", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite 0.29.0", + "webpki-roots 0.26.11", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.4", + "rustls", + "rustls-pki-types", + "sha1 0.10.6", + "thiserror 2.0.18", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.4", + "rustls", + "rustls-pki-types", + "sha1 0.10.6", + "thiserror 2.0.18", +] + +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +dependencies = [ + "rand 0.9.4", +] + +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "ulid" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" +dependencies = [ + "rand 0.9.4", + "web-time", +] + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +dependencies = [ + "base64", + "der", + "flate2", + "log", + "native-tls", + "percent-encoding", + "rustls-pki-types", + "ureq-proto", + "utf8-zero", + "webpki-root-certs", +] + +[[package]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" + +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "rand 0.10.1", + "serde_core", + "wasm-bindgen", + "zerocopy", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "semver", +] + +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + +[[package]] +name = "web-sys" +version = "0.3.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", +] + +[[package]] +name = "webpki-roots" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.14.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.14.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.14.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zip" +version = "8.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +dependencies = [ + "aes 0.9.0", + "bzip2", + "constant_time_eq", + "crc32fast", + "deflate64", + "flate2", + "getrandom 0.4.2", + "hmac", + "indexmap 2.14.0", + "lzma-rust2", + "memchr", + "pbkdf2", + "ppmd-rust", + "sha1 0.11.0", + "time", + "typed-path", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/foreign/php/Cargo.toml b/foreign/php/Cargo.toml new file mode 100644 index 0000000000..fea889679e --- /dev/null +++ b/foreign/php/Cargo.toml @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +[package] +name = "iggy-php" +version = "0.1.0" +edition = "2024" +authors = ["Iggy Committers "] +license = "Apache-2.0" +description = "PHP extension bindings for Apache Iggy." +documentation = "https://iggy.apache.org/docs/" +repository = "https://github.com/apache/iggy" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +bytes = "1.11.1" +futures = "0.3.32" +ext-php-rs = "0.15.13" +iggy = { path = "../../core/sdk", version = "0.10.0" } +php-tokio = { git = "https://github.com/danog/php-tokio.git", tag = "0.1.11" } +tokio = "1.50.0" + +[profile.release] +strip = "debuginfo" diff --git a/foreign/php/Dockerfile.test b/foreign/php/Dockerfile.test new file mode 100644 index 0000000000..e927efdf47 --- /dev/null +++ b/foreign/php/Dockerfile.test @@ -0,0 +1,59 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +FROM rust:1.95-slim-bookworm + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + composer \ + curl \ + git \ + clang \ + libclang-dev \ + libssl-dev \ + php-cli \ + php-dev \ + pkg-config \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +ENV PHP=/usr/bin/php +ENV PHP_CONFIG=/usr/bin/php-config +ENV IGGY_HOST=iggy-server +ENV IGGY_PORT=8090 + +WORKDIR /workspace + +COPY Cargo.toml Cargo.lock ./ +COPY core/ ./core/ + +COPY foreign/php/Cargo.toml foreign/php/Cargo.lock ./foreign/php/ +COPY foreign/php/composer.json foreign/php/composer.lock ./foreign/php/ +COPY foreign/php/README.md foreign/php/LICENSE foreign/php/NOTICE ./foreign/php/ +COPY foreign/php/.cargo/ ./foreign/php/.cargo/ +COPY foreign/php/src/ ./foreign/php/src/ +COPY foreign/php/tests/ ./foreign/php/tests/ +COPY foreign/php/scripts/ ./foreign/php/scripts/ + +WORKDIR /workspace/foreign/php + +RUN composer install --no-interaction --no-progress --prefer-dist +RUN cargo install cargo-php --locked +RUN cargo php install --release --yes +RUN chmod +x ./scripts/test.sh + +CMD ["./scripts/test.sh"] diff --git a/foreign/php/LICENSE b/foreign/php/LICENSE new file mode 100644 index 0000000000..8dada3edaf --- /dev/null +++ b/foreign/php/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/foreign/php/NOTICE b/foreign/php/NOTICE new file mode 100644 index 0000000000..cc8d194800 --- /dev/null +++ b/foreign/php/NOTICE @@ -0,0 +1,12 @@ +Apache Iggy (Incubating) +Copyright 2026 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +================================================================ + +The Iggy project code was originally created, designed, developed by Piotr Gankiewicz in April 2023. +It was released as an open-source project under MIT License, later converted to Apache 2.0 License, +and donated by LaserData, Inc. to the Apache Software Foundation (ASF) in February 2025. +Copyright April 2023 - February 2025 Piotr Gankiewicz, LaserData, Inc. diff --git a/foreign/php/README.md b/foreign/php/README.md new file mode 100644 index 0000000000..aabba19d1f --- /dev/null +++ b/foreign/php/README.md @@ -0,0 +1,202 @@ +# iggy-php + +PHP extension bindings for [Apache Iggy](https://iggy.apache.org/), built in Rust with +[`ext-php-rs`](https://github.com/davidcole1340/ext-php-rs). + +This repository is experimental. The extension exposes two PHP clients over the Rust +Iggy client: + +- `IggyClient`: blocking, synchronous PHP API. +- `IggyAsyncClient`: Fiber/Revolt-aware API powered by `php-tokio`. + +## Requirements + +- Rust and Cargo +- PHP with `php-config` +- `cargo-php` +- Composer, for async test dependencies +- Docker, for running the integration test server + +On macOS with Homebrew PHP: + +```sh +export PATH="/opt/homebrew/opt/php/bin:$PATH" +export PHP=/opt/homebrew/opt/php/bin/php +export PHP_CONFIG=/opt/homebrew/opt/php/bin/php-config +``` + +## Build + +```sh +cargo build --release +``` + +## Install + +```sh +cargo php install --release --yes +``` + +If the extension is already enabled, reinstall it with: + +```sh +cargo php remove --yes +cargo php install --release --yes +``` + +Verify PHP can load it: + +```sh +php -r 'var_dump(extension_loaded("iggy-php"));' +``` + +## Run Iggy + +```sh +docker run --rm --name iggy-php-test \ + -p 8090:8090 \ + -p 3000:3000 \ + apache/iggy:latest +``` + +The tests assume: + +- host: `127.0.0.1` +- port: `8090` +- username: `iggy` +- password: `iggy` + +Override them with `IGGY_HOST`, `IGGY_PORT`, `IGGY_USERNAME`, and `IGGY_PASSWORD`. + +## Usage + +### Synchronous Client + +```php +connect(); +$client->loginUser('iggy', 'iggy'); + +$stream = 'php-stream'; +$topic = 'php-topic'; +$partitionId = 0; + +$client->createStream($stream); +$client->createTopic($stream, $topic, 1, null, null, null, null); + +$client->sendMessages($stream, $topic, $partitionId, [ + new SendMessage('hello from PHP'), +]); + +$messages = $client->pollMessages( + $stream, + $topic, + $partitionId, + PollingStrategy::first(), + 10, + true, +); + +foreach ($messages as $message) { + echo $message->payload(), PHP_EOL; +} +``` + +### Async Client + +`IggyAsyncClient` integrates Tokio with PHP Fibers through +[`php-tokio`](https://github.com/danog/php-tokio) and Revolt. The methods look like +normal PHP calls, but they suspend the current Fiber while the Rust future is pending. + +Install the PHP event-loop dependencies: + +```sh +composer install +``` + +Register the file descriptor returned by `IggyAsyncClient::init()` with Revolt and call +`IggyAsyncClient::wakeup()` when it becomes readable: + +```php + IggyAsyncClient::wakeup(), +); + +try { + $future = async(function () { + $client = new IggyAsyncClient('127.0.0.1:8090'); + $client->connect(); + $client->loginUser('iggy', 'iggy'); + $client->ping(); + + return 'pong'; + }); + + echo $future->await(), PHP_EOL; +} finally { + EventLoop::cancel($watcher); + fclose($readable); + IggyAsyncClient::shutdown(); +} +``` + +The async client covers the core connection, stream, topic, send, poll, and +consumer-group operations. `IggyAsyncConsumer::iterMessages()->next()` and +`IggyAsyncConsumer::consumeMessages()` suspend the current Fiber while waiting for +messages. + +## Tests + +Run the Dockerized integration suite: + +```sh +docker compose -f docker-compose.test.yml up --build --abort-on-container-exit --exit-code-from php-tests +``` + +Run the PHP test suite: + +```sh +php tests/run.php +``` + +Async tests require Composer dependencies: + +```sh +composer install +php tests/run.php IggyAsyncSdkTest +``` + +Run Rust verification: + +```sh +cargo test +``` + +TLS tests are opt-in because they require a TLS-enabled Iggy server and certificate +setup. Set `IGGY_TLS_CONNECTION_STRING` to enable TLS connection tests. Set +`IGGY_TLS_PLAINTEXT_ADDRESS` to run the negative plaintext-to-TLS test. + +## API Notes + +- Methods are exposed to PHP as camelCase, for example `createStream()` and + `pollMessages()`. +- Partition IDs use the Iggy partition index. For a topic with one partition, use `0`. +- Large unsigned values that can overflow PHP integers, such as message checksums, + are returned as decimal strings. +- `IggyClient` is synchronous and blocks the current PHP thread. +- `IggyAsyncClient` is Fiber/Revolt-aware. Its methods must be called after + `IggyAsyncClient::init()` and from a Fiber-aware runtime such as Amp/Revolt. diff --git a/foreign/php/composer.json b/foreign/php/composer.json new file mode 100644 index 0000000000..461f951882 --- /dev/null +++ b/foreign/php/composer.json @@ -0,0 +1,13 @@ +{ + "name": "apache/iggy-php", + "description": "PHP extension bindings for Apache Iggy.", + "license": "Apache-2.0", + "type": "library", + "require-dev": { + "amphp/amp": "^3.0", + "revolt/event-loop": "^1.0" + }, + "scripts": { + "test": "php tests/run.php" + } +} diff --git a/foreign/php/composer.lock b/foreign/php/composer.lock new file mode 100644 index 0000000000..b2f220982c --- /dev/null +++ b/foreign/php/composer.lock @@ -0,0 +1,172 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "3842dabaa05a2bd5fbaa193d589fc790", + "packages": [], + "packages-dev": [ + { + "name": "amphp/amp", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Future/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "https://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-08-27T21:42:00+00:00" + }, + { + "name": "revolt/event-loop", + "version": "v1.0.8", + "source": { + "type": "git", + "url": "https://github.com/revoltphp/event-loop.git", + "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/b6fc06dce8e9b523c9946138fa5e62181934f91c", + "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Revolt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Rock-solid event loop for concurrent PHP applications.", + "keywords": [ + "async", + "asynchronous", + "concurrency", + "event", + "event-loop", + "non-blocking", + "scheduler" + ], + "support": { + "issues": "https://github.com/revoltphp/event-loop/issues", + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.8" + }, + "time": "2025-08-27T21:33:23+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} diff --git a/foreign/php/docker-compose.test.yml b/foreign/php/docker-compose.test.yml new file mode 100644 index 0000000000..b64a924fe0 --- /dev/null +++ b/foreign/php/docker-compose.test.yml @@ -0,0 +1,66 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +services: + iggy-server: + build: + context: ../.. + dockerfile: core/server/Dockerfile + args: + PROFILE: debug + container_name: iggy-server-php-test + security_opt: + - seccomp:unconfined + networks: + - php-test-network + ports: + - "3000:3000" + - "8080:8080" + - "8090:8090" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/stats"] + interval: 5s + timeout: 5s + retries: 12 + start_period: 10s + volumes: + - iggy-data:/local_data + + php-tests: + build: + context: ../.. + dockerfile: foreign/php/Dockerfile.test + container_name: php-sdk-tests + depends_on: + iggy-server: + condition: service_healthy + networks: + - php-test-network + environment: + - IGGY_HOST=iggy-server + - IGGY_PORT=8090 + - IGGY_USERNAME=iggy + - IGGY_PASSWORD=iggy + volumes: + - ./test-results:/workspace/foreign/php/test-results + +networks: + php-test-network: + name: php-test-network + +volumes: + iggy-data: diff --git a/foreign/php/scripts/test.sh b/foreign/php/scripts/test.sh new file mode 100755 index 0000000000..626738a3fb --- /dev/null +++ b/foreign/php/scripts/test.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -euo pipefail + +echo "PHP SDK Test Runner" +echo "===================" + +IGGY_HOST="${IGGY_HOST:-127.0.0.1}" +IGGY_PORT="${IGGY_PORT:-8090}" + +echo "Waiting for Iggy server at ${IGGY_HOST}:${IGGY_PORT}..." +timeout 60 bash -c " + until timeout 5 bash -c ' = Result; + +/// A Fiber/Revolt-aware PHP client for Iggy. +/// +/// Methods suspend the current PHP Fiber while the Rust Tokio future is pending. +/// Use `IggyAsyncClient::init()` and `IggyAsyncClient::wakeup()` to bridge Tokio +/// readiness notifications into the PHP event loop. +#[php_class] +pub struct IggyAsyncClient { + inner: Arc, +} + +#[php_impl] +impl IggyAsyncClient { + /// Constructs a new async client from a TCP server address. + #[php(constructor)] + pub fn __construct(conn: Option) -> PhpResult { + let client = IggyClientBuilder::new() + .with_tcp() + .with_server_address(conn.unwrap_or_else(|| "127.0.0.1:8090".to_string())) + .build() + .map_err(to_php_exception)?; + + Ok(Self { + inner: Arc::new(client), + }) + } + + /// Initializes the php-tokio bridge and returns a readable file descriptor. + /// + /// Register this descriptor with Revolt and call `IggyAsyncClient::wakeup()` + /// whenever it becomes readable. + pub fn init() -> PhpResult { + EventLoop::init() + } + + /// Resumes PHP Fibers whose Tokio futures have completed. + pub fn wakeup() -> PhpResult { + EventLoop::wakeup() + } + + /// Clears the thread-local php-tokio bridge state. + pub fn shutdown() { + EventLoop::shutdown(); + } + + /// Constructs a new async client from a connection string. + pub fn from_connection_string(connection_string: String) -> PhpResult { + let client = + RustIggyClient::from_connection_string(&connection_string).map_err(to_php_exception)?; + + Ok(Self { + inner: Arc::new(client), + }) + } + + /// Sends a ping request to the server. + pub fn ping(&self) -> AsyncPhpResult { + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { inner.ping().await.map_err(to_async_exception) }) + } + + /// Logs in the user with the given credentials. + pub fn login_user(&self, username: String, password: String) -> AsyncPhpResult { + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .login_user(&username, &password) + .await + .map(|_| ()) + .map_err(to_async_exception) + }) + } + + /// Connects the client to its service. + pub fn connect(&self) -> AsyncPhpResult { + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { inner.connect().await.map_err(to_async_exception) }) + } + + /// Creates a new stream. + pub fn create_stream(&self, name: String) -> AsyncPhpResult { + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .create_stream(&name) + .await + .map(|_| ()) + .map_err(to_async_exception) + }) + } + + /// Gets a stream by id or name. + pub fn get_stream(&self, stream_id: PhpIdentifier) -> AsyncPhpResult> { + let stream_id = Identifier::from(stream_id); + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .get_stream(&stream_id) + .await + .map(|stream| stream.map(StreamDetails::from)) + .map_err(to_async_exception) + }) + } + + /// Creates a topic. + /// + /// message_expiry_micros is null for server default. + #[allow(clippy::too_many_arguments)] + pub fn create_topic( + &self, + stream: PhpIdentifier, + name: String, + partitions_count: u32, + compression_algorithm: Option, + replication_factor: Option, + message_expiry_micros: Option, + max_topic_size: Option, + ) -> AsyncPhpResult { + let compression_algorithm = match compression_algorithm { + Some(value) => CompressionAlgorithm::from_str(&value).map_err(to_async_exception)?, + None => CompressionAlgorithm::default(), + }; + let expiry = message_expiry_micros.map_or(IggyExpiry::ServerDefault, |micros| { + IggyExpiry::ExpireDuration(iggy_duration_from_micros(micros)) + }); + let max_size = max_topic_size.map_or(MaxTopicSize::ServerDefault, MaxTopicSize::from); + let stream = Identifier::from(stream); + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .create_topic( + &stream, + &name, + partitions_count, + compression_algorithm, + replication_factor, + expiry, + max_size, + ) + .await + .map(|_| ()) + .map_err(to_async_exception) + }) + } + + /// Gets a topic by stream and topic id/name. + pub fn get_topic( + &self, + stream_id: PhpIdentifier, + topic_id: PhpIdentifier, + ) -> AsyncPhpResult> { + let stream_id = Identifier::from(stream_id); + let topic_id = Identifier::from(topic_id); + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .get_topic(&stream_id, &topic_id) + .await + .map(|topic| topic.map(TopicDetails::from)) + .map_err(to_async_exception) + }) + } + + /// Sends messages to a topic. + pub fn send_messages( + &self, + stream: PhpIdentifier, + topic: PhpIdentifier, + partition_id: u32, + messages: Vec<&SendMessage>, + ) -> AsyncPhpResult { + let stream = Identifier::from(stream); + let topic = Identifier::from(topic); + let partitioning = Partitioning::partition_id(partition_id); + let mut messages: Vec = messages + .into_iter() + .map(|message| (*message).clone().inner) + .collect(); + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .send_messages(&stream, &topic, &partitioning, messages.as_mut()) + .await + .map_err(to_async_exception) + }) + } + + /// Polls messages from the specified topic and partition. + pub fn poll_messages( + &self, + stream: PhpIdentifier, + topic: PhpIdentifier, + partition_id: u32, + polling_strategy: &PollingStrategy, + count: u32, + auto_commit: bool, + ) -> AsyncPhpResult> { + let consumer = RustConsumer::default(); + let stream = Identifier::from(stream); + let topic = Identifier::from(topic); + let strategy: RustPollingStrategy = polling_strategy.into(); + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + let polled_messages = inner + .poll_messages( + &stream, + &topic, + Some(partition_id), + &consumer, + &strategy, + count, + auto_commit, + ) + .await + .map_err(to_async_exception)?; + + Ok(polled_messages + .messages + .into_iter() + .map(|message| ReceiveMessage { + inner: message, + partition_id, + }) + .collect()) + }) + } + + /// Creates and initializes a consumer group consumer. + #[allow(clippy::too_many_arguments)] + pub fn consumer_group( + &self, + name: String, + stream: String, + topic: String, + partition_id: Option, + polling_strategy: Option<&PollingStrategy>, + batch_length: Option, + auto_commit: Option<&AutoCommit>, + create_consumer_group_if_not_exists: bool, + auto_join_consumer_group: bool, + poll_interval_micros: Option, + polling_retry_interval_micros: Option, + init_retries: Option, + init_retry_interval_micros: Option, + allow_replay: bool, + ) -> AsyncPhpResult { + let mut builder = self + .inner + .consumer_group(&name, &stream, &topic) + .map_err(to_async_exception)? + .without_encryptor() + .partition(partition_id); + + builder = if create_consumer_group_if_not_exists { + builder.create_consumer_group_if_not_exists() + } else { + builder.do_not_create_consumer_group_if_not_exists() + }; + builder = if auto_join_consumer_group { + builder.auto_join_consumer_group() + } else { + builder.do_not_auto_join_consumer_group() + }; + if let Some(polling_strategy) = polling_strategy { + builder = builder.polling_strategy(polling_strategy.into()); + } + if let Some(batch_length) = batch_length { + builder = builder.batch_length(batch_length); + } + if let Some(auto_commit) = auto_commit { + builder = builder.auto_commit(auto_commit.into()); + } + builder = match poll_interval_micros { + Some(micros) => builder.poll_interval(iggy_duration_from_micros(micros)), + None => builder.without_poll_interval(), + }; + if let Some(micros) = polling_retry_interval_micros { + builder = builder.polling_retry_interval(iggy_duration_from_micros(micros)); + } + + match (init_retries, init_retry_interval_micros) { + (Some(retries), Some(micros)) => { + builder = builder.init_retries(retries, iggy_duration_from_micros(micros)); + } + (Some(_), None) => { + return Err( + "'init_retry_interval_micros' is required if 'init_retries' is set".to_string(), + ); + } + (None, Some(_)) => { + return Err( + "'init_retries' is required if 'init_retry_interval_micros' is set".to_string(), + ); + } + (None, None) => {} + } + if allow_replay { + builder = builder.allow_replay(); + } + + let mut consumer = builder.build(); + EventLoop::suspend_on(async move { + consumer.init().await.map_err(to_async_exception)?; + Ok(IggyAsyncConsumer { + inner: Arc::new(Mutex::new(consumer)), + }) + }) + } +} + +pub unsafe extern "C" fn request_shutdown(_type: i32, _module_number: i32) -> i32 { + EventLoop::shutdown(); + 0 +} + +fn to_php_exception(error: impl std::fmt::Display) -> PhpException { + PhpException::default(error.to_string()) +} + +fn to_async_exception(error: impl std::fmt::Display) -> String { + error.to_string() +} + +fn iggy_duration_from_micros(micros: u64) -> IggyDuration { + IggyDuration::new(Duration::from_micros(micros)) +} diff --git a/foreign/php/src/async_consumer.rs b/foreign/php/src/async_consumer.rs new file mode 100644 index 0000000000..f516b63831 --- /dev/null +++ b/foreign/php/src/async_consumer.rs @@ -0,0 +1,166 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use std::sync::Arc; + +use ext_php_rs::{php_class, php_impl, types::ZendCallable}; +use futures::StreamExt; +use iggy::prelude::IggyConsumer as RustIggyConsumer; +use php_tokio::EventLoop; +use tokio::sync::Mutex; + +use crate::receive_message::ReceiveMessage; + +type AsyncPhpResult = Result; + +#[php_class] +pub struct IggyAsyncConsumer { + pub(crate) inner: Arc>, +} + +#[php_impl] +impl IggyAsyncConsumer { + /// Get the last consumed offset or null if no offset has been consumed yet. + pub fn get_last_consumed_offset(&self, partition_id: u32) -> Option { + self.inner + .blocking_lock() + .get_last_consumed_offset(partition_id) + } + + /// Get the last stored offset or null if no offset has been stored yet. + pub fn get_last_stored_offset(&self, partition_id: u32) -> Option { + self.inner + .blocking_lock() + .get_last_stored_offset(partition_id) + } + + /// Gets the name of the consumer group. + pub fn name(&self) -> String { + self.inner.blocking_lock().name().to_string() + } + + /// Gets the current partition id or 0 if no messages have been polled yet. + pub fn partition_id(&self) -> u32 { + self.inner.blocking_lock().partition_id() + } + + /// Gets the stream identifier this consumer is configured for. + pub fn stream(&self) -> String { + self.inner.blocking_lock().stream().to_string() + } + + /// Gets the topic identifier this consumer is configured for. + pub fn topic(&self) -> String { + self.inner.blocking_lock().topic().to_string() + } + + /// Stores the provided offset for the provided partition id. + /// + /// If partition_id is null, the current partition id is used. + pub fn store_offset(&self, offset: u64, partition_id: Option) -> AsyncPhpResult { + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .lock() + .await + .store_offset(offset, partition_id) + .await + .map_err(to_async_exception) + }) + } + + /// Deletes the stored offset for the provided partition id. + /// + /// If partition_id is null, the current partition id is used. + pub fn delete_offset(&self, partition_id: Option) -> AsyncPhpResult { + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + inner + .lock() + .await + .delete_offset(partition_id) + .await + .map_err(to_async_exception) + }) + } + + /// Returns an iterator whose next() method suspends until a message is available. + pub fn iter_messages(&self) -> IggyAsyncReceiveMessageIterator { + IggyAsyncReceiveMessageIterator { + inner: self.inner.clone(), + } + } + + /// Consumes messages with a PHP callback. + /// + /// The callback is called as callback(ReceiveMessage $message). If limit is null, + /// this method runs until the consumer stream ends or an error occurs. + pub fn consume_messages( + &self, + callback: ZendCallable, + limit: Option, + ) -> AsyncPhpResult { + let mut consumed = 0; + let max_messages = limit.unwrap_or(u32::MAX); + let iterator = self.iter_messages(); + + while consumed < max_messages { + let Some(message) = iterator.next()? else { + break; + }; + + callback + .try_call(vec![&message]) + .map_err(|err| err.to_string())?; + consumed += 1; + } + + Ok(consumed) + } +} + +#[php_class] +pub struct IggyAsyncReceiveMessageIterator { + pub(crate) inner: Arc>, +} + +#[php_impl] +impl IggyAsyncReceiveMessageIterator { + pub fn next(&self) -> AsyncPhpResult> { + let inner = self.inner.clone(); + + EventLoop::suspend_on(async move { + let mut inner = inner.lock().await; + + match inner.next().await { + Some(Ok(message)) => Ok(Some(ReceiveMessage { + inner: message.message, + partition_id: message.partition_id, + })), + Some(Err(err)) => Err(err.to_string()), + None => Ok(None), + } + }) + } +} + +fn to_async_exception(error: impl std::fmt::Display) -> String { + error.to_string() +} diff --git a/foreign/php/src/client.rs b/foreign/php/src/client.rs new file mode 100644 index 0000000000..0945532b21 --- /dev/null +++ b/foreign/php/src/client.rs @@ -0,0 +1,350 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use std::{str::FromStr, sync::Arc, time::Duration}; + +use ext_php_rs::{ + exception::{PhpException, PhpResult}, + php_class, php_impl, +}; +use iggy::prelude::{ + CompressionAlgorithm, Consumer as RustConsumer, Identifier, IggyClient as RustIggyClient, + IggyClientBuilder, IggyDuration, IggyExpiry, IggyMessage as RustMessage, MaxTopicSize, + Partitioning, PollingStrategy as RustPollingStrategy, *, +}; +use tokio::sync::Mutex; + +use crate::consumer::{AutoCommit, IggyConsumer}; +use crate::identifier::PhpIdentifier; +use crate::receive_message::{PollingStrategy, ReceiveMessage}; +use crate::send_message::SendMessage; +use crate::stream::StreamDetails; +use crate::topic::TopicDetails; + +/// A PHP class representing the Iggy client. +#[php_class] +pub struct IggyClient { + inner: Arc, +} + +#[php_impl] +impl IggyClient { + /// Constructs a new IggyClient from a TCP server address. + #[php(constructor)] + pub fn __construct(conn: Option) -> PhpResult { + let client = IggyClientBuilder::new() + .with_tcp() + .with_server_address(conn.unwrap_or_else(|| "127.0.0.1:8090".to_string())) + .build() + .map_err(to_php_exception)?; + + Ok(Self { + inner: Arc::new(client), + }) + } + + /// Constructs a new IggyClient from a connection string. + pub fn from_connection_string(connection_string: String) -> PhpResult { + let client = + RustIggyClient::from_connection_string(&connection_string).map_err(to_php_exception)?; + + Ok(Self { + inner: Arc::new(client), + }) + } + + /// Sends a ping request to the server. + pub fn ping(&self) -> PhpResult { + let inner = self.inner.clone(); + runtime().block_on(async move { inner.ping().await.map_err(to_php_exception) }) + } + + /// Logs in the user with the given credentials. + pub fn login_user(&self, username: String, password: String) -> PhpResult { + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .login_user(&username, &password) + .await + .map(|_| ()) + .map_err(to_php_exception) + }) + } + + /// Connects the IggyClient to its service. + pub fn connect(&self) -> PhpResult { + let inner = self.inner.clone(); + runtime().block_on(async move { inner.connect().await.map_err(to_php_exception) }) + } + + /// Creates a new stream. + pub fn create_stream(&self, name: String) -> PhpResult { + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .create_stream(&name) + .await + .map(|_| ()) + .map_err(to_php_exception) + }) + } + + /// Gets a stream by id or name. + pub fn get_stream(&self, stream_id: PhpIdentifier) -> PhpResult> { + let stream_id = Identifier::from(stream_id); + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .get_stream(&stream_id) + .await + .map(|stream| stream.map(StreamDetails::from)) + .map_err(to_php_exception) + }) + } + + /// Creates a topic. + /// + /// message_expiry_micros is null for server default. + #[allow(clippy::too_many_arguments)] + pub fn create_topic( + &self, + stream: PhpIdentifier, + name: String, + partitions_count: u32, + compression_algorithm: Option, + replication_factor: Option, + message_expiry_micros: Option, + max_topic_size: Option, + ) -> PhpResult { + let compression_algorithm = match compression_algorithm { + Some(value) => CompressionAlgorithm::from_str(&value).map_err(to_php_exception)?, + None => CompressionAlgorithm::default(), + }; + let expiry = message_expiry_micros.map_or(IggyExpiry::ServerDefault, |micros| { + IggyExpiry::ExpireDuration(iggy_duration_from_micros(micros)) + }); + let max_size = max_topic_size.map_or(MaxTopicSize::ServerDefault, MaxTopicSize::from); + let stream = Identifier::from(stream); + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .create_topic( + &stream, + &name, + partitions_count, + compression_algorithm, + replication_factor, + expiry, + max_size, + ) + .await + .map(|_| ()) + .map_err(to_php_exception) + }) + } + + /// Gets a topic by stream and topic id/name. + pub fn get_topic( + &self, + stream_id: PhpIdentifier, + topic_id: PhpIdentifier, + ) -> PhpResult> { + let stream_id = Identifier::from(stream_id); + let topic_id = Identifier::from(topic_id); + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .get_topic(&stream_id, &topic_id) + .await + .map(|topic| topic.map(TopicDetails::from)) + .map_err(to_php_exception) + }) + } + + /// Sends messages to a topic. + pub fn send_messages( + &self, + stream: PhpIdentifier, + topic: PhpIdentifier, + partition_id: u32, + messages: Vec<&SendMessage>, + ) -> PhpResult { + let stream = Identifier::from(stream); + let topic = Identifier::from(topic); + let partitioning = Partitioning::partition_id(partition_id); + let mut messages: Vec = messages + .into_iter() + .map(|message| (*message).clone().inner) + .collect(); + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .send_messages(&stream, &topic, &partitioning, messages.as_mut()) + .await + .map_err(to_php_exception) + }) + } + + /// Polls messages from the specified topic and partition. + pub fn poll_messages( + &self, + stream: PhpIdentifier, + topic: PhpIdentifier, + partition_id: u32, + polling_strategy: &PollingStrategy, + count: u32, + auto_commit: bool, + ) -> PhpResult> { + let consumer = RustConsumer::default(); + let stream = Identifier::from(stream); + let topic = Identifier::from(topic); + let strategy: RustPollingStrategy = polling_strategy.into(); + let inner = self.inner.clone(); + + runtime().block_on(async move { + let polled_messages = inner + .poll_messages( + &stream, + &topic, + Some(partition_id), + &consumer, + &strategy, + count, + auto_commit, + ) + .await + .map_err(to_php_exception)?; + + Ok(polled_messages + .messages + .into_iter() + .map(|message| ReceiveMessage { + inner: message, + partition_id, + }) + .collect()) + }) + } + + /// Creates and initializes a consumer group consumer. + #[allow(clippy::too_many_arguments)] + pub fn consumer_group( + &self, + name: String, + stream: String, + topic: String, + partition_id: Option, + polling_strategy: Option<&PollingStrategy>, + batch_length: Option, + auto_commit: Option<&AutoCommit>, + create_consumer_group_if_not_exists: bool, + auto_join_consumer_group: bool, + poll_interval_micros: Option, + polling_retry_interval_micros: Option, + init_retries: Option, + init_retry_interval_micros: Option, + allow_replay: bool, + ) -> PhpResult { + let mut builder = self + .inner + .consumer_group(&name, &stream, &topic) + .map_err(to_php_exception)? + .without_encryptor() + .partition(partition_id); + + builder = if create_consumer_group_if_not_exists { + builder.create_consumer_group_if_not_exists() + } else { + builder.do_not_create_consumer_group_if_not_exists() + }; + builder = if auto_join_consumer_group { + builder.auto_join_consumer_group() + } else { + builder.do_not_auto_join_consumer_group() + }; + if let Some(polling_strategy) = polling_strategy { + builder = builder.polling_strategy(polling_strategy.into()); + } + if let Some(batch_length) = batch_length { + builder = builder.batch_length(batch_length); + } + if let Some(auto_commit) = auto_commit { + builder = builder.auto_commit(auto_commit.into()); + } + builder = match poll_interval_micros { + Some(micros) => builder.poll_interval(iggy_duration_from_micros(micros)), + None => builder.without_poll_interval(), + }; + if let Some(micros) = polling_retry_interval_micros { + builder = builder.polling_retry_interval(iggy_duration_from_micros(micros)); + } + + match (init_retries, init_retry_interval_micros) { + (Some(retries), Some(micros)) => { + builder = builder.init_retries(retries, iggy_duration_from_micros(micros)); + } + (Some(_), None) => { + return Err( + "'init_retry_interval_micros' is required if 'init_retries' is set".into(), + ); + } + (None, Some(_)) => { + return Err( + "'init_retries' is required if 'init_retry_interval_micros' is set".into(), + ); + } + (None, None) => {} + } + if allow_replay { + builder = builder.allow_replay(); + } + + let mut consumer = builder.build(); + runtime().block_on(async move { + consumer.init().await.map_err(to_php_exception)?; + Ok(IggyConsumer { + inner: Arc::new(Mutex::new(consumer)), + }) + }) + } +} + +fn to_php_exception(error: impl std::fmt::Display) -> PhpException { + PhpException::default(error.to_string()) +} + +fn iggy_duration_from_micros(micros: u64) -> IggyDuration { + IggyDuration::new(Duration::from_micros(micros)) +} + +fn runtime() -> &'static tokio::runtime::Runtime { + static RUNTIME: std::sync::OnceLock = std::sync::OnceLock::new(); + + RUNTIME.get_or_init(|| { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .expect("failed to initialize Tokio runtime") + }) +} diff --git a/foreign/php/src/consumer.rs b/foreign/php/src/consumer.rs new file mode 100644 index 0000000000..12cdc89248 --- /dev/null +++ b/foreign/php/src/consumer.rs @@ -0,0 +1,280 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use std::{sync::Arc, time::Duration}; + +use ext_php_rs::{ + exception::{PhpException, PhpResult}, + php_class, php_impl, + types::ZendCallable, +}; +use iggy::prelude::{ + AutoCommit as RustAutoCommit, AutoCommitAfter as RustAutoCommitAfter, + AutoCommitWhen as RustAutoCommitWhen, IggyConsumer as RustIggyConsumer, IggyDuration, +}; +use tokio::sync::Mutex; + +use crate::iterator::ReceiveMessageIterator; + +/// A PHP class representing the Iggy consumer. +#[php_class] +pub struct IggyConsumer { + pub(crate) inner: Arc>, +} + +#[php_impl] +impl IggyConsumer { + /// Get the last consumed offset or null if no offset has been consumed yet. + pub fn get_last_consumed_offset(&self, partition_id: u32) -> Option { + self.inner + .blocking_lock() + .get_last_consumed_offset(partition_id) + } + + /// Get the last stored offset or null if no offset has been stored yet. + pub fn get_last_stored_offset(&self, partition_id: u32) -> Option { + self.inner + .blocking_lock() + .get_last_stored_offset(partition_id) + } + + /// Gets the name of the consumer group. + pub fn name(&self) -> String { + self.inner.blocking_lock().name().to_string() + } + + /// Gets the current partition id or 0 if no messages have been polled yet. + pub fn partition_id(&self) -> u32 { + self.inner.blocking_lock().partition_id() + } + + /// Gets the stream identifier this consumer is configured for. + pub fn stream(&self) -> String { + self.inner.blocking_lock().stream().to_string() + } + + /// Gets the topic identifier this consumer is configured for. + pub fn topic(&self) -> String { + self.inner.blocking_lock().topic().to_string() + } + + /// Stores the provided offset for the provided partition id. + /// + /// If partition_id is null, the current partition id is used. + pub fn store_offset(&self, offset: u64, partition_id: Option) -> PhpResult { + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .lock() + .await + .store_offset(offset, partition_id) + .await + .map_err(|err| PhpException::default(err.to_string())) + }) + } + + /// Deletes the stored offset for the provided partition id. + /// + /// If partition_id is null, the current partition id is used. + pub fn delete_offset(&self, partition_id: Option) -> PhpResult { + let inner = self.inner.clone(); + + runtime().block_on(async move { + inner + .lock() + .await + .delete_offset(partition_id) + .await + .map_err(|err| PhpException::default(err.to_string())) + }) + } + + /// Returns an iterator whose next() method blocks until a message is available. + pub fn iter_messages(&self) -> ReceiveMessageIterator { + ReceiveMessageIterator { + inner: self.inner.clone(), + } + } + + /// Consumes messages with a PHP callback. + /// + /// The callback is called as callback(ReceiveMessage $message). If limit is null, + /// this method runs until the consumer stream ends or an error occurs. + pub fn consume_messages(&self, callback: ZendCallable, limit: Option) -> PhpResult { + let mut consumed = 0; + let max_messages = limit.unwrap_or(u32::MAX); + + while consumed < max_messages { + let Some(message) = self.iter_messages().next()? else { + break; + }; + + callback + .try_call(vec![&message]) + .map_err(|err| PhpException::default(err.to_string()))?; + consumed += 1; + } + + Ok(consumed) + } +} + +#[php_class] +#[derive(Clone, Copy)] +pub struct AutoCommit { + pub(crate) inner: RustAutoCommit, +} + +#[php_impl] +impl AutoCommit { + pub fn disabled() -> Self { + Self { + inner: RustAutoCommit::Disabled, + } + } + + pub fn interval(interval_micros: u64) -> Self { + Self { + inner: RustAutoCommit::Interval(iggy_duration_from_micros(interval_micros)), + } + } + + pub fn interval_or_when(interval_micros: u64, when: &AutoCommitWhen) -> Self { + Self { + inner: RustAutoCommit::IntervalOrWhen( + iggy_duration_from_micros(interval_micros), + when.inner, + ), + } + } + + pub fn interval_or_after(interval_micros: u64, after: &AutoCommitAfter) -> Self { + Self { + inner: RustAutoCommit::IntervalOrAfter( + iggy_duration_from_micros(interval_micros), + after.inner, + ), + } + } + + pub fn when(when: &AutoCommitWhen) -> Self { + Self { + inner: RustAutoCommit::When(when.inner), + } + } + + pub fn after(after: &AutoCommitAfter) -> Self { + Self { + inner: RustAutoCommit::After(after.inner), + } + } +} + +impl From<&AutoCommit> for RustAutoCommit { + fn from(value: &AutoCommit) -> Self { + value.inner + } +} + +#[php_class] +#[derive(Clone, Copy)] +pub struct AutoCommitWhen { + pub(crate) inner: RustAutoCommitWhen, +} + +#[php_impl] +impl AutoCommitWhen { + pub fn polling_messages() -> Self { + Self { + inner: RustAutoCommitWhen::PollingMessages, + } + } + + pub fn consuming_all_messages() -> Self { + Self { + inner: RustAutoCommitWhen::ConsumingAllMessages, + } + } + + pub fn consuming_each_message() -> Self { + Self { + inner: RustAutoCommitWhen::ConsumingEachMessage, + } + } + + pub fn consuming_every_nth_message(n: u32) -> Self { + Self { + inner: RustAutoCommitWhen::ConsumingEveryNthMessage(n), + } + } +} + +impl From<&AutoCommitWhen> for RustAutoCommitWhen { + fn from(value: &AutoCommitWhen) -> Self { + value.inner + } +} + +#[php_class] +#[derive(Clone, Copy)] +pub struct AutoCommitAfter { + pub(crate) inner: RustAutoCommitAfter, +} + +#[php_impl] +impl AutoCommitAfter { + pub fn consuming_all_messages() -> Self { + Self { + inner: RustAutoCommitAfter::ConsumingAllMessages, + } + } + + pub fn consuming_each_message() -> Self { + Self { + inner: RustAutoCommitAfter::ConsumingEachMessage, + } + } + + pub fn consuming_every_nth_message(n: u32) -> Self { + Self { + inner: RustAutoCommitAfter::ConsumingEveryNthMessage(n), + } + } +} + +impl From<&AutoCommitAfter> for RustAutoCommitAfter { + fn from(value: &AutoCommitAfter) -> Self { + value.inner + } +} + +fn iggy_duration_from_micros(micros: u64) -> IggyDuration { + IggyDuration::new(Duration::from_micros(micros)) +} + +fn runtime() -> &'static tokio::runtime::Runtime { + static RUNTIME: std::sync::OnceLock = std::sync::OnceLock::new(); + + RUNTIME.get_or_init(|| { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .expect("failed to initialize Tokio runtime") + }) +} diff --git a/foreign/php/src/identifier.rs b/foreign/php/src/identifier.rs new file mode 100644 index 0000000000..9087c2728a --- /dev/null +++ b/foreign/php/src/identifier.rs @@ -0,0 +1,59 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use std::str::FromStr; + +use ext_php_rs::{convert::FromZval, flags::DataType, types::Zval}; +use iggy::prelude::{IdKind, Identifier}; + +pub enum PhpIdentifier { + String(String), + Int(u32), +} + +impl FromZval<'_> for PhpIdentifier { + const TYPE: DataType = DataType::Mixed; + + fn from_zval(zval: &Zval) -> Option { + if let Some(value) = zval.string() { + return Some(Self::String(value)); + } + + zval.long() + .and_then(|value| u32::try_from(value).ok()) + .map(Self::Int) + } +} + +impl From for Identifier { + fn from(identifier: PhpIdentifier) -> Self { + match identifier { + PhpIdentifier::String(value) => Identifier::from_str(&value).unwrap(), + PhpIdentifier::Int(value) => Identifier::numeric(value).unwrap(), + } + } +} + +impl From<&Identifier> for PhpIdentifier { + fn from(value: &Identifier) -> PhpIdentifier { + match value.kind { + IdKind::String => PhpIdentifier::String(value.get_string_value().unwrap()), + IdKind::Numeric => PhpIdentifier::Int(value.get_u32_value().unwrap()), + } + } +} diff --git a/foreign/php/src/iterator.rs b/foreign/php/src/iterator.rs new file mode 100644 index 0000000000..fa599bdedf --- /dev/null +++ b/foreign/php/src/iterator.rs @@ -0,0 +1,65 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use std::{sync::Arc, sync::OnceLock}; + +use ext_php_rs::{ + exception::{PhpException, PhpResult}, + php_class, php_impl, +}; +use futures::StreamExt; +use iggy::prelude::IggyConsumer as RustIggyConsumer; +use tokio::{runtime::Runtime, sync::Mutex}; + +use crate::receive_message::ReceiveMessage; + +#[php_class] +pub struct ReceiveMessageIterator { + pub(crate) inner: Arc>, +} + +#[php_impl] +impl ReceiveMessageIterator { + pub fn next(&self) -> PhpResult> { + let inner = self.inner.clone(); + + runtime().block_on(async move { + let mut inner = inner.lock().await; + + match inner.next().await { + Some(Ok(message)) => Ok(Some(ReceiveMessage { + inner: message.message, + partition_id: message.partition_id, + })), + Some(Err(err)) => Err(PhpException::default(err.to_string())), + None => Ok(None), + } + }) + } +} + +pub fn runtime() -> &'static Runtime { + static RUNTIME: OnceLock = OnceLock::new(); + + RUNTIME.get_or_init(|| { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .expect("failed to initialize Tokio runtime") + }) +} diff --git a/foreign/php/src/lib.rs b/foreign/php/src/lib.rs new file mode 100644 index 0000000000..ec5283d5e7 --- /dev/null +++ b/foreign/php/src/lib.rs @@ -0,0 +1,60 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +pub mod async_client; +pub mod async_consumer; +pub mod client; +pub mod consumer; +pub mod identifier; +pub mod iterator; +pub mod receive_message; +pub mod send_message; +pub mod stream; +pub mod topic; + +use ext_php_rs::prelude::*; + +use crate::async_client::IggyAsyncClient; +use crate::async_consumer::{IggyAsyncConsumer, IggyAsyncReceiveMessageIterator}; +use crate::client::IggyClient; +use crate::consumer::{AutoCommit, AutoCommitAfter, AutoCommitWhen, IggyConsumer}; +use crate::iterator::ReceiveMessageIterator; +use crate::receive_message::{PollingStrategy, ReceiveMessage}; +use crate::send_message::SendMessage; +use crate::stream::StreamDetails; +use crate::topic::TopicDetails; + +#[php_module] +pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { + module + .request_shutdown_function(crate::async_client::request_shutdown) + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() + .class::() +} diff --git a/foreign/php/src/receive_message.rs b/foreign/php/src/receive_message.rs new file mode 100644 index 0000000000..71c071ca18 --- /dev/null +++ b/foreign/php/src/receive_message.rs @@ -0,0 +1,148 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use ext_php_rs::{binary::Binary, php_class, php_impl}; +use iggy::prelude::{ + IggyMessage as RustReceiveMessage, IggyMessageHeader, PollingStrategy as RustPollingStrategy, +}; + +/// A Python class representing a received message. +/// +/// This class wraps a Rust message, allowing for access to its payload and offset from Python. +#[php_class] +pub struct ReceiveMessage { + pub(crate) inner: RustReceiveMessage, + pub(crate) partition_id: u32, +} + +impl Clone for ReceiveMessage { + fn clone(&self) -> Self { + Self { + inner: RustReceiveMessage { + header: IggyMessageHeader { + checksum: self.inner.header.checksum, + id: self.inner.header.id, + offset: self.inner.header.offset, + timestamp: self.inner.header.timestamp, + origin_timestamp: self.inner.header.origin_timestamp, + user_headers_length: self.inner.header.user_headers_length, + payload_length: self.inner.header.payload_length, + reserved: self.inner.header.reserved, + }, + payload: self.inner.payload.clone(), + user_headers: self.inner.user_headers.clone(), + }, + partition_id: self.partition_id, + } + } +} + +#[php_impl] +impl ReceiveMessage { + /// Retrieves the payload of the received message. + /// + /// The payload is returned as a PHP string, which can represent both text and binary data. + pub fn payload(&self) -> Binary { + Binary::new(self.inner.payload.to_vec()) + } + + /// Retrieves the offset of the received message. + /// + /// The offset represents the position of the message within its topic. + pub fn offset(&self) -> u64 { + self.inner.header.offset + } + + /// Retrieves the timestamp of the received message. + /// + /// The timestamp represents the time of the message within its topic. + pub fn timestamp(&self) -> u64 { + self.inner.header.timestamp + } + + /// Retrieves the id of the received message. + /// + /// The id represents unique identifier of the message within its topic. + pub fn id(&self) -> String { + self.inner.header.id.to_string() + } + + /// Retrieves the checksum of the received message. + /// + /// The checksum represents the integrity of the message within its topic. + pub fn checksum(&self) -> String { + self.inner.header.checksum.to_string() + } + + /// Retrieves the length of the received message. + /// + /// The length represents the length of the payload. + pub fn length(&self) -> u32 { + self.inner.header.payload_length + } + + /// Retrieves the partition this message belongs to. + pub fn partition_id(&self) -> u32 { + self.partition_id + } +} + +#[php_class] +#[derive(Clone)] +pub struct PollingStrategy { + pub(crate) inner: RustPollingStrategy, +} + +impl From<&PollingStrategy> for RustPollingStrategy { + fn from(value: &PollingStrategy) -> Self { + value.inner + } +} + +#[php_impl] +impl PollingStrategy { + pub fn offset(value: u64) -> Self { + Self { + inner: RustPollingStrategy::offset(value), + } + } + + pub fn timestamp(value: u64) -> Self { + Self { + inner: RustPollingStrategy::timestamp(value.into()), + } + } + + pub fn first() -> Self { + Self { + inner: RustPollingStrategy::first(), + } + } + + pub fn last() -> Self { + Self { + inner: RustPollingStrategy::last(), + } + } + + pub fn next() -> Self { + Self { + inner: RustPollingStrategy::next(), + } + } +} diff --git a/foreign/php/src/send_message.rs b/foreign/php/src/send_message.rs new file mode 100644 index 0000000000..07638d5480 --- /dev/null +++ b/foreign/php/src/send_message.rs @@ -0,0 +1,84 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use bytes::Bytes; +use ext_php_rs::{ + binary::Binary, + exception::{PhpException, PhpResult}, + php_class, php_impl, +}; +use iggy::prelude::{IggyMessage as RustIggyMessage, IggyMessageHeader}; + +/// A PHP class representing a message to be sent. +#[php_class] +pub struct SendMessage { + pub(crate) inner: RustIggyMessage, +} + +impl Clone for SendMessage { + fn clone(&self) -> Self { + Self { + inner: RustIggyMessage { + header: IggyMessageHeader { + checksum: self.inner.header.checksum, + id: self.inner.header.id, + offset: self.inner.header.offset, + timestamp: self.inner.header.timestamp, + origin_timestamp: self.inner.header.origin_timestamp, + user_headers_length: self.inner.header.user_headers_length, + payload_length: self.inner.header.payload_length, + reserved: self.inner.header.reserved, + }, + payload: self.inner.payload.clone(), + user_headers: self.inner.user_headers.clone(), + }, + } + } +} + +#[php_impl] +impl SendMessage { + /// Constructs a new `SendMessage` instance from a PHP string. + /// + /// PHP strings are byte strings, so this accepts both text and binary payloads. + #[php(constructor)] + pub fn __construct(data: Binary) -> PhpResult { + Self::from_payload(Vec::from(data)) + } + + #[php(getter)] + pub fn id(&self) -> String { + self.inner.header.id.to_string() + } + + #[php(getter)] + pub fn payload(&self) -> Binary { + Binary::new(self.inner.payload.to_vec()) + } +} + +impl SendMessage { + fn from_payload(payload: Vec) -> PhpResult { + let inner = RustIggyMessage::builder() + .payload(Bytes::from(payload)) + .build() + .map_err(|err| PhpException::default(err.to_string()))?; + + Ok(Self { inner }) + } +} diff --git a/foreign/php/src/stream.rs b/foreign/php/src/stream.rs new file mode 100644 index 0000000000..5da29fb27a --- /dev/null +++ b/foreign/php/src/stream.rs @@ -0,0 +1,56 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use ext_php_rs::{php_class, php_impl}; +use iggy::prelude::StreamDetails as RustStreamDetails; + +#[php_class] +pub struct StreamDetails { + pub(crate) inner: RustStreamDetails, +} + +impl From for StreamDetails { + fn from(stream_details: RustStreamDetails) -> Self { + Self { + inner: stream_details, + } + } +} + +#[php_impl] +impl StreamDetails { + #[php(getter)] + pub fn id(&self) -> u32 { + self.inner.id + } + + #[php(getter)] + pub fn name(&self) -> String { + self.inner.name.to_string() + } + + #[php(getter)] + pub fn messages_count(&self) -> u64 { + self.inner.messages_count + } + + #[php(getter)] + pub fn topics_count(&self) -> u32 { + self.inner.topics_count + } +} diff --git a/foreign/php/src/topic.rs b/foreign/php/src/topic.rs new file mode 100644 index 0000000000..89c20b988a --- /dev/null +++ b/foreign/php/src/topic.rs @@ -0,0 +1,54 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use ext_php_rs::{php_class, php_impl}; +use iggy::prelude::TopicDetails as RustTopicDetails; + +#[php_class] +pub struct TopicDetails { + pub(crate) inner: RustTopicDetails, +} + +impl From for TopicDetails { + fn from(inner: RustTopicDetails) -> Self { + Self { inner } + } +} + +#[php_impl] +impl TopicDetails { + #[php(getter)] + pub fn id(&self) -> u32 { + self.inner.id + } + + #[php(getter)] + pub fn name(&self) -> String { + self.inner.name.to_string() + } + + #[php(getter)] + pub fn messages_count(&self) -> u64 { + self.inner.messages_count + } + + #[php(getter)] + pub fn partitions_count(&self) -> u32 { + self.inner.partitions_count + } +} diff --git a/foreign/php/tests/IggyAsyncSdkTest.php b/foreign/php/tests/IggyAsyncSdkTest.php new file mode 100644 index 0000000000..519428b94e --- /dev/null +++ b/foreign/php/tests/IggyAsyncSdkTest.php @@ -0,0 +1,195 @@ +connect(); + $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + $client->ping(); + }); + } + + public function testAsyncSendAndPollMessages(): void + { + run_async(function (): void { + $client = new IggyAsyncClient(server_host() . ':' . server_port()); + $client->connect(); + $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + + $streamName = unique_name('async-msg-stream'); + $topicName = unique_name('async-msg-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Async message {$i} - {$streamName}", + range(1, 3), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $polled = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::first(), 10, true); + assert_true(count($polled) >= count($messages), 'expected at least the sent async messages'); + assert_same($messages, array_slice(collect_payloads($polled), 0, count($messages))); + }); + } + + public function testAsyncConsumerGroupMeta(): void + { + run_async(function (): void { + $client = new IggyAsyncClient(server_host() . ':' . server_port()); + $client->connect(); + $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + + $consumerName = unique_name('async-consumer-group-consumer'); + $streamName = unique_name('async-consumer-group-stream'); + $topicName = unique_name('async-consumer-group-topic'); + $partitionId = 0; + + create_stream_and_topic($client, $streamName, $topicName); + $consumer = $this->consumerGroup($client, $consumerName, $streamName, $topicName, $partitionId); + + assert_true($consumer instanceof IggyAsyncConsumer); + assert_same($streamName, $consumer->stream()); + assert_same($topicName, $consumer->topic()); + assert_same(0, $consumer->partitionId()); + assert_null($consumer->getLastConsumedOffset($partitionId)); + assert_null($consumer->getLastStoredOffset($partitionId)); + }); + } + + public function testAsyncConsumeMessages(): void + { + run_async(function (): void { + $client = new IggyAsyncClient(server_host() . ':' . server_port()); + $client->connect(); + $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + + $consumerName = unique_name('async-consumer-group-consumer'); + $streamName = unique_name('async-consumer-group-stream'); + $topicName = unique_name('async-consumer-group-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Async consumer group test {$i} - {$streamName}", + range(0, 4), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $consumer = $this->consumerGroup($client, $consumerName, $streamName, $topicName, $partitionId); + $received = []; + $count = $consumer->consumeMessages( + static function (ReceiveMessage $message) use (&$received): void { + $received[] = $message->payload(); + }, + count($messages), + ); + + assert_same(count($messages), $count); + assert_same($messages, $received); + }); + } + + public function testAsyncIterMessages(): void + { + run_async(function (): void { + $client = new IggyAsyncClient(server_host() . ':' . server_port()); + $client->connect(); + $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + + $consumerName = unique_name('async-consumer-group-consumer'); + $streamName = unique_name('async-consumer-group-stream'); + $topicName = unique_name('async-consumer-group-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Async iterator test {$i} - {$streamName}", + range(0, 4), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $consumer = $this->consumerGroup($client, $consumerName, $streamName, $topicName, $partitionId); + $iterator = $consumer->iterMessages(); + assert_true($iterator instanceof IggyAsyncReceiveMessageIterator); + + $received = []; + while (count($received) < count($messages)) { + $message = $iterator->next(); + assert_not_null($message); + $received[] = $message->payload(); + } + + assert_same($messages, $received); + }); + } + + private function consumerGroup( + IggyAsyncClient $client, + string $consumerName, + string $streamName, + string $topicName, + int $partitionId, + ): IggyAsyncConsumer { + return $client->consumerGroup( + $consumerName, + $streamName, + $topicName, + $partitionId, + PollingStrategy::next(), + 10, + AutoCommit::interval(micros(5)), + true, + true, + micros(1), + null, + null, + null, + false, + ); + } +} diff --git a/foreign/php/tests/IggySdkTest.php b/foreign/php/tests/IggySdkTest.php new file mode 100644 index 0000000000..dfa3d57c34 --- /dev/null +++ b/foreign/php/tests/IggySdkTest.php @@ -0,0 +1,364 @@ +ping(); + } + + public function testClientNotNull(): void + { + assert_true(new_client() instanceof IggyClient); + } + + public function testClientFromConnectionString(): void + { + $client = new_connection_string_client(); + $client->ping(); + } + + public function testCreateAndGetStream(): void + { + $client = new_client(); + $streamName = unique_name('test-stream'); + + $client->createStream($streamName); + $stream = $client->getStream($streamName); + + assert_not_null($stream); + assert_same($streamName, $stream->name); + assert_true($stream->id >= 0, 'expected non-negative stream id'); + } + + public function testNewStreamHasNoTopics(): void + { + $client = new_client(); + $streamName = unique_name('test-stream'); + + $client->createStream($streamName); + $stream = $client->getStream($streamName); + + assert_not_null($stream); + assert_same($streamName, $stream->name); + assert_true($stream->id > 0, 'expected positive stream id'); + assert_same(0, $stream->topics_count); + } + + public function testCreateAndGetTopic(): void + { + $client = new_client(); + $streamName = unique_name('test-stream'); + $topicName = unique_name('test-topic'); + + $client->createStream($streamName); + $client->createTopic($streamName, $topicName, 2, null, null, null, null); + $topic = $client->getTopic($streamName, $topicName); + + assert_not_null($topic); + assert_same($topicName, $topic->name); + assert_true($topic->id >= 0, 'expected non-negative topic id'); + assert_same(2, $topic->partitions_count); + } + + public function testListTopicsViaGetTopic(): void + { + $client = new_client(); + $streamName = unique_name('test-stream'); + $topicName = unique_name('test-topic'); + + create_stream_and_topic($client, $streamName, $topicName); + $topic = $client->getTopic($streamName, $topicName); + + assert_not_null($topic); + assert_same($topicName, $topic->name); + assert_true($topic->id >= 0, 'expected non-negative topic id'); + assert_same(1, $topic->partitions_count); + } + + public function testSendAndPollMessages(): void + { + $client = new_client(); + $streamName = unique_name('msg-stream'); + $topicName = unique_name('msg-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Test message {$i} - {$streamName}", + range(1, 3), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $polled = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::first(), 10, true); + assert_true(count($polled) >= count($messages), 'expected at least the sent messages'); + assert_same($messages, array_slice(collect_payloads($polled), 0, count($messages))); + } + + public function testSendAndPollMessagesAsBytes(): void + { + $client = new_client(); + $streamName = unique_name('msg-stream'); + $topicName = unique_name('msg-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Binary message {$i} - {$streamName}", + range(1, 3), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $polled = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::first(), 10, true); + assert_true(count($polled) >= count($messages), 'expected at least the sent messages'); + assert_same($messages, array_slice(collect_payloads($polled), 0, count($messages))); + } + + public function testMessageProperties(): void + { + $client = new_client(); + $streamName = unique_name('msg-stream'); + $topicName = unique_name('msg-topic'); + $partitionId = 0; + $payload = unique_name('Property test'); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages($streamName, $topicName, $partitionId, [new SendMessage($payload)]); + + $polled = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::last(), 1, true); + assert_true(count($polled) >= 1, 'expected one message'); + + $message = $polled[0]; + assert_same($payload, $message->payload()); + assert_true($message->offset() >= 0, 'expected non-negative offset'); + assert_true($message->id() !== '', 'expected message id'); + assert_true($message->timestamp() > 0, 'expected positive timestamp'); + assert_true(ctype_digit($message->checksum()), 'expected numeric checksum'); + assert_true($message->length() > 0, 'expected positive length'); + assert_same($partitionId, $message->partitionId()); + } + + public function testPollingStrategies(): void + { + $client = new_client(); + $streamName = unique_name('poll-stream'); + $topicName = unique_name('poll-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Polling test {$i} - {$streamName}", + range(0, 4), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $firstMessages = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::first(), 1, false); + assert_true(count($firstMessages) >= 1, 'first strategy returned no messages'); + + $lastMessages = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::last(), 1, false); + assert_true(count($lastMessages) >= 1, 'last strategy returned no messages'); + + $nextMessages = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::next(), 2, false); + assert_true(count($nextMessages) >= 1, 'next strategy returned no messages'); + + $offsetMessages = $client->pollMessages( + $streamName, + $topicName, + $partitionId, + PollingStrategy::offset($firstMessages[0]->offset()), + 1, + false, + ); + assert_true(count($offsetMessages) >= 1, 'offset strategy returned no messages'); + } + + public function testDuplicateStreamCreation(): void + { + $client = new_client(); + $streamName = unique_name('duplicate-test'); + + $client->createStream($streamName); + assert_throws(static fn () => $client->createStream($streamName), 'already exists'); + } + + public function testGetNonexistentStream(): void + { + $stream = new_client()->getStream(unique_name('nonexistent')); + + assert_null($stream); + } + + public function testCreateTopicInNonexistentStream(): void + { + $client = new_client(); + + assert_throws( + static fn () => $client->createTopic(unique_name('nonexistent'), 'test-topic', 1, null, null, null, null), + ); + } + + public function testConsumerGroupMeta(): void + { + $client = new_client(); + $consumerName = unique_name('consumer-group-consumer'); + $streamName = unique_name('consumer-group-stream'); + $topicName = unique_name('consumer-group-topic'); + $partitionId = 0; + + create_stream_and_topic($client, $streamName, $topicName); + $consumer = $client->consumerGroup( + $consumerName, + $streamName, + $topicName, + $partitionId, + PollingStrategy::next(), + 10, + AutoCommit::interval(micros(5)), + true, + true, + micros(1), + null, + null, + null, + false, + ); + + assert_same($streamName, $consumer->stream()); + assert_same($topicName, $consumer->topic()); + assert_same(0, $consumer->partitionId()); + assert_null($consumer->getLastConsumedOffset($partitionId)); + assert_null($consumer->getLastStoredOffset($partitionId)); + } + + public function testConsumeMessages(): void + { + $client = new_client(); + $consumerName = unique_name('consumer-group-consumer'); + $streamName = unique_name('consumer-group-stream'); + $topicName = unique_name('consumer-group-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Consumer group test {$i} - {$streamName}", + range(0, 4), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $consumer = $client->consumerGroup( + $consumerName, + $streamName, + $topicName, + $partitionId, + PollingStrategy::next(), + 10, + AutoCommit::interval(micros(5)), + true, + true, + micros(1), + null, + null, + null, + false, + ); + $received = []; + $count = $consumer->consumeMessages( + static function (ReceiveMessage $message) use (&$received): void { + $received[] = $message->payload(); + }, + count($messages), + ); + + assert_same(count($messages), $count); + assert_same($messages, $received); + } + + public function testIterMessages(): void + { + $client = new_client(); + $consumerName = unique_name('consumer-group-consumer'); + $streamName = unique_name('consumer-group-stream'); + $topicName = unique_name('consumer-group-topic'); + $partitionId = 0; + $messages = array_map( + static fn (int $i): string => "Iterator test {$i} - {$streamName}", + range(0, 4), + ); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $consumer = $client->consumerGroup( + $consumerName, + $streamName, + $topicName, + $partitionId, + PollingStrategy::next(), + 10, + AutoCommit::interval(micros(5)), + true, + true, + micros(1), + null, + null, + null, + false, + ); + + $iterator = $consumer->iterMessages(); + $received = []; + while (count($received) < count($messages)) { + $message = $iterator->next(); + assert_not_null($message); + $received[] = $message->payload(); + } + + assert_same($messages, $received); + } +} diff --git a/foreign/php/tests/TlsTest.php b/foreign/php/tests/TlsTest.php new file mode 100644 index 0000000000..4798bdee2b --- /dev/null +++ b/foreign/php/tests/TlsTest.php @@ -0,0 +1,82 @@ +connect(); + $client->ping(); + } + + public function testProduceAndConsumeOverTls(): void + { + $connectionString = getenv('IGGY_TLS_CONNECTION_STRING'); + if ($connectionString === false || $connectionString === '') { + throw new SkippedTest('set IGGY_TLS_CONNECTION_STRING to run TLS tests'); + } + + $client = IggyClient::fromConnectionString($connectionString); + $client->connect(); + $client->ping(); + + $streamName = unique_name('tls-msg-stream'); + $topicName = unique_name('tls-test-topic'); + $partitionId = 0; + $messages = array_map(static fn (int $i): string => "tls-message-{$i}", range(0, 2)); + + create_stream_and_topic($client, $streamName, $topicName); + $client->sendMessages( + $streamName, + $topicName, + $partitionId, + array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), + ); + + $polled = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::first(), 10, true); + assert_true(count($polled) >= count($messages), 'expected TLS messages'); + assert_same($messages, array_slice(collect_payloads($polled), 0, count($messages))); + } + + public function testConnectWithoutTlsShouldFail(): void + { + $address = getenv('IGGY_TLS_PLAINTEXT_ADDRESS'); + if ($address === false || $address === '') { + throw new SkippedTest('set IGGY_TLS_PLAINTEXT_ADDRESS to run this TLS failure test'); + } + + $client = new IggyClient($address); + assert_throws(static fn () => $client->connect()); + } +} + +final class SkippedTest extends RuntimeException +{ +} + diff --git a/foreign/php/tests/bootstrap.php b/foreign/php/tests/bootstrap.php new file mode 100644 index 0000000000..f04ab8c61c --- /dev/null +++ b/foreign/php/tests/bootstrap.php @@ -0,0 +1,198 @@ +getMessage(), $messageContains)) { + throw new TestFailure( + 'expected exception message to contain ' . var_export($messageContains, true) + . ', got ' . var_export($throwable->getMessage(), true) + ); + } + + return $throwable; + } + + throw new TestFailure('expected callable to throw'); +} + +function unique_name(string $prefix): string +{ + return $prefix . '-' . bin2hex(random_bytes(4)); +} + +function env_or_default(string $name, string $default): string +{ + $value = getenv($name); + + return $value === false || $value === '' ? $default : $value; +} + +function server_host(): string +{ + return env_or_default('IGGY_HOST', '127.0.0.1'); +} + +function server_port(): int +{ + return (int) env_or_default('IGGY_PORT', '8090'); +} + +function wait_for_server(string $host, int $port, int $timeoutSeconds = 30): void +{ + $deadline = microtime(true) + $timeoutSeconds; + $lastError = null; + + while (microtime(true) < $deadline) { + $socket = @fsockopen($host, $port, $errno, $errstr, 1.0); + if (is_resource($socket)) { + fclose($socket); + + return; + } + + $lastError = trim($errstr !== '' ? $errstr : (string) $errno); + usleep(250_000); + } + + throw new TestFailure("Iggy server was not reachable at {$host}:{$port}" . ($lastError !== null ? " ({$lastError})" : '')); +} + +function new_client(): IggyClient +{ + $client = new IggyClient(server_host() . ':' . server_port()); + $client->connect(); + $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); + + return $client; +} + +function new_connection_string_client(): IggyClient +{ + $host = server_host(); + $port = server_port(); + $username = rawurlencode(env_or_default('IGGY_USERNAME', 'iggy')); + $password = rawurlencode(env_or_default('IGGY_PASSWORD', 'iggy')); + + $client = IggyClient::fromConnectionString("iggy+tcp://{$username}:{$password}@{$host}:{$port}"); + $client->connect(); + + return $client; +} + +function create_stream_and_topic(object $client, string $stream, string $topic, int $partitions = 1): void +{ + $client->createStream($stream); + $client->createTopic($stream, $topic, $partitions, null, null, null, null); +} + +function collect_payloads(array $messages): array +{ + return array_map(static fn (ReceiveMessage $message): string => $message->payload(), $messages); +} + +function micros(int $seconds): int +{ + return $seconds * 1_000_000; +} + +function load_async_dependencies(): void +{ + if (class_exists('\\Revolt\\EventLoop') && function_exists('\\Amp\\async')) { + return; + } + + $autoload = dirname(__DIR__) . '/vendor/autoload.php'; + if (!is_file($autoload)) { + throw new SkippedTest('run composer install to install Revolt/Amp async test dependencies'); + } + + require_once $autoload; + + if (!class_exists('\\Revolt\\EventLoop') || !function_exists('\\Amp\\async')) { + throw new SkippedTest('Revolt/Amp async test dependencies are unavailable'); + } +} + +function run_async(callable $callback): mixed +{ + load_async_dependencies(); + + $fd = IggyAsyncClient::init(); + $stream = fopen('php://fd/' . $fd, 'r'); + if ($stream === false) { + throw new TestFailure('failed to open php-tokio readiness fd'); + } + stream_set_blocking($stream, false); + + $watcher = \Revolt\EventLoop::onReadable( + $stream, + static fn (): null => IggyAsyncClient::wakeup(), + ); + + try { + $future = \Amp\async($callback); + + return $future->await(); + } finally { + \Revolt\EventLoop::cancel($watcher); + fclose($stream); + IggyAsyncClient::shutdown(); + } +} diff --git a/foreign/php/tests/run.php b/foreign/php/tests/run.php new file mode 100644 index 0000000000..a9b644f359 --- /dev/null +++ b/foreign/php/tests/run.php @@ -0,0 +1,81 @@ +getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + if (!str_starts_with($method->getName(), 'test')) { + continue; + } + + $name = $class . '::' . $method->getName(); + if ($filter !== null && !str_contains($name, $filter)) { + continue; + } + + try { + $method->invoke($instance); + $passed++; + fwrite(STDOUT, "PASS {$name}\n"); + } catch (ReflectionException $exception) { + $failed++; + fwrite(STDERR, "FAIL {$name}: {$exception->getMessage()}\n"); + } catch (Throwable $throwable) { + $previous = $throwable instanceof ReflectionException ? $throwable->getPrevious() : null; + $error = $previous ?? $throwable; + + if ($error instanceof SkippedTest) { + $skipped++; + fwrite(STDOUT, "SKIP {$name}: {$error->getMessage()}\n"); + continue; + } + + $failed++; + fwrite(STDERR, "FAIL {$name}: {$error->getMessage()}\n"); + } + } +} + +fwrite(STDOUT, "\n{$passed} passed, {$skipped} skipped, {$failed} failed\n"); +exit($failed === 0 ? 0 : 1); From 0311699d8a7fd2d99cb93b042fd07570a0309912 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Tue, 12 May 2026 08:29:00 +0300 Subject: [PATCH 2/7] Make foreign SDK test servers reachable in Compose The PHP and Python SDK integration suites depend on a server container that can be checked for readiness and reached from sibling containers. The previous healthcheck hit an authenticated HTTP endpoint with curl, while the runtime image did not install curl and the default server binds loopback-only addresses. The compose files now start the server with default root credentials, bind service ports to all interfaces, and use the bundled CLI ping for readiness. Constraint: Runtime image should not need extra healthcheck packages just for foreign SDK tests Constraint: SDK test containers connect through the Docker service name, not the server container loopback interface Rejected: Install curl and keep /stats healthcheck | /stats requires authentication and does not prove TCP SDK readiness Confidence: high Scope-risk: narrow Directive: Keep foreign SDK compose server bind addresses aligned with client container hostnames Tested: docker compose config for PHP and Python test files; git diff --check Not-tested: Full Docker build/test run locally because Docker daemon was unavailable --- foreign/php/docker-compose.test.yml | 8 +++++++- foreign/python/docker-compose.test.yml | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/foreign/php/docker-compose.test.yml b/foreign/php/docker-compose.test.yml index b64a924fe0..492779feac 100644 --- a/foreign/php/docker-compose.test.yml +++ b/foreign/php/docker-compose.test.yml @@ -22,9 +22,15 @@ services: dockerfile: core/server/Dockerfile args: PROFILE: debug + command: ["--fresh", "--with-default-root-credentials"] container_name: iggy-server-php-test security_opt: - seccomp:unconfined + environment: + - IGGY_HTTP_ADDRESS=0.0.0.0:3000 + - IGGY_TCP_ADDRESS=0.0.0.0:8090 + - IGGY_QUIC_ADDRESS=0.0.0.0:8080 + - IGGY_WEBSOCKET_ADDRESS=0.0.0.0:8092 networks: - php-test-network ports: @@ -32,7 +38,7 @@ services: - "8080:8080" - "8090:8090" healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/stats"] + test: ["CMD", "/usr/local/bin/iggy", "--tcp-server-address", "127.0.0.1:8090", "ping"] interval: 5s timeout: 5s retries: 12 diff --git a/foreign/python/docker-compose.test.yml b/foreign/python/docker-compose.test.yml index 92ffec6daf..005857d2ab 100644 --- a/foreign/python/docker-compose.test.yml +++ b/foreign/python/docker-compose.test.yml @@ -24,7 +24,13 @@ services: dockerfile: core/server/Dockerfile args: PROFILE: debug + command: ["--fresh", "--with-default-root-credentials"] container_name: iggy-server-python-test + environment: + - IGGY_HTTP_ADDRESS=0.0.0.0:3000 + - IGGY_TCP_ADDRESS=0.0.0.0:8090 + - IGGY_QUIC_ADDRESS=0.0.0.0:8080 + - IGGY_WEBSOCKET_ADDRESS=0.0.0.0:8092 networks: - python-test-network ports: @@ -32,7 +38,7 @@ services: - "8080:8080" - "8090:8090" healthcheck: - test: [ "CMD", "curl", "-f", "http://localhost:3000/stats" ] + test: [ "CMD", "/usr/local/bin/iggy", "--tcp-server-address", "127.0.0.1:8090", "ping" ] interval: 5s timeout: 5s retries: 12 From aec298357c6f125bafa2495aea793389688c05b3 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Tue, 12 May 2026 08:30:09 +0300 Subject: [PATCH 3/7] Update .gitignore --- foreign/php/.gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/foreign/php/.gitignore b/foreign/php/.gitignore index 9b5cec80ec..1edade7b58 100644 --- a/foreign/php/.gitignore +++ b/foreign/php/.gitignore @@ -1,4 +1,2 @@ /target -.omx/ /vendor -/test-results From f162f52756601750a7bc8814b003a0a06b433afb Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Tue, 12 May 2026 15:13:09 +0300 Subject: [PATCH 4/7] Reduce PHP SDK PR to reviewable blocking client The PHP SDK addition was too large and carried an async bridge plus Docker-heavy CI path in the first review. This narrows the PR to the blocking client, removes async-only dependencies and lockfiles, and moves PHP checks into a language-specific pre-merge action that reports into the existing CI status gate. Constraint: Reviewer requested the async client be split out to reduce LoC and review risk Constraint: PHP CI must avoid the previous 22 minute Docker Compose path Rejected: Keep async client in this PR | too much surface area and an extra php-tokio dependency for initial review Rejected: Keep inline PHP workflow steps | inconsistent with other SDK CI actions and missed status aggregation Confidence: high Scope-risk: moderate Directive: Reintroduce IggyAsyncClient in a separate PR after the blocking client and CI path settle Tested: Ruby YAML parse for workflows/actions; PHP syntax checks; composer.json JSON parse; cargo fmt --manifest-path foreign/php/Cargo.toml -- --check; Docker PHP test image build Not-tested: Full GitHub Actions runtime duration --- .github/actions/php/pre-merge/action.yml | 125 + .github/config/components.yml | 2 +- .github/workflows/_test.yml | 17 +- .github/workflows/pre-merge.yml | 6 + foreign/php/.gitignore | 2 + foreign/php/Cargo.lock | 5479 ---------------------- foreign/php/Cargo.toml | 1 - foreign/php/Dockerfile.test | 6 +- foreign/php/README.md | 74 +- foreign/php/composer.json | 4 - foreign/php/composer.lock | 172 - foreign/php/scripts/test.sh | 8 +- foreign/php/src/async_client.rs | 376 -- foreign/php/src/async_consumer.rs | 166 - foreign/php/src/lib.rs | 8 - foreign/php/tests/IggyAsyncSdkTest.php | 195 - foreign/php/tests/bootstrap.php | 45 - foreign/php/tests/run.php | 3 +- 18 files changed, 150 insertions(+), 6539 deletions(-) create mode 100644 .github/actions/php/pre-merge/action.yml delete mode 100644 foreign/php/Cargo.lock delete mode 100644 foreign/php/composer.lock delete mode 100644 foreign/php/src/async_client.rs delete mode 100644 foreign/php/src/async_consumer.rs delete mode 100644 foreign/php/tests/IggyAsyncSdkTest.php diff --git a/.github/actions/php/pre-merge/action.yml b/.github/actions/php/pre-merge/action.yml new file mode 100644 index 0000000000..174a51d013 --- /dev/null +++ b/.github/actions/php/pre-merge/action.yml @@ -0,0 +1,125 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: php-pre-merge +description: PHP pre-merge testing github iggy actions + +inputs: + task: + description: "Task to run (lint, test, build)" + required: true + +runs: + using: "composite" + steps: + - name: Install PHP build dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + clang \ + libclang-dev \ + libssl-dev \ + php-cli \ + php-dev \ + pkg-config \ + unzip + + echo "PHP=$(command -v php)" >> "$GITHUB_ENV" + echo "PHP_CONFIG=$(command -v php-config)" >> "$GITHUB_ENV" + php --version + php-config --version + + - name: Setup Rust with cache + uses: ./.github/actions/utils/setup-rust-with-cache + with: + shared-key: dev + save-cache: ${{ inputs.task == 'test' }} + + - name: Use shared Cargo target directory + shell: bash + run: echo "CARGO_TARGET_DIR=${GITHUB_WORKSPACE}/target" >> "$GITHUB_ENV" + + - name: Validate task + shell: bash + run: | + case "${{ inputs.task }}" in + lint|test|build) ;; + *) + echo "Unknown PHP SDK task: ${{ inputs.task }}" + exit 1 + ;; + esac + + - name: Lint + if: inputs.task == 'lint' + shell: bash + run: | + php -r 'json_decode(file_get_contents("foreign/php/composer.json"), true, 512, JSON_THROW_ON_ERROR);' + cargo fmt --manifest-path foreign/php/Cargo.toml -- --check + find foreign/php \ + -path foreign/php/vendor -prune -o \ + -name '*.php' -print0 \ + | xargs -0 -n1 php -l + + - name: Build PHP extension + if: inputs.task == 'build' + shell: bash + run: | + cargo build --release --manifest-path foreign/php/Cargo.toml + extension="$(find "${CARGO_TARGET_DIR}/release" -maxdepth 1 -name 'libiggy_php.so' -print -quit)" + if [ -z "$extension" ]; then + echo "PHP extension was not produced" + exit 1 + fi + ls -lh "$extension" + + - name: Build PHP extension for tests + if: inputs.task == 'test' + shell: bash + run: | + cargo build --manifest-path foreign/php/Cargo.toml + extension="$(find "${CARGO_TARGET_DIR}/debug" -maxdepth 1 -name 'libiggy_php.so' -print -quit)" + if [ -z "$extension" ]; then + echo "PHP extension was not produced" + exit 1 + fi + echo "IGGY_PHP_EXTENSION=$(realpath "$extension")" >> "$GITHUB_ENV" + ls -lh "$extension" + + - name: Start Iggy server + if: inputs.task == 'test' + id: iggy + uses: ./.github/actions/utils/server-start + + - name: Run PHP SDK tests + if: inputs.task == 'test' + shell: bash + working-directory: foreign/php + env: + IGGY_HOST: 127.0.0.1 + IGGY_PORT: 8090 + IGGY_USERNAME: iggy + IGGY_PASSWORD: iggy + run: ./scripts/test.sh + + - name: Stop Iggy server + if: always() && inputs.task == 'test' + uses: ./.github/actions/utils/server-stop + with: + pid-file: ${{ steps.iggy.outputs.pid_file }} + log-file: ${{ steps.iggy.outputs.log_file }} diff --git a/.github/config/components.yml b/.github/config/components.yml index 4b709f0a6f..fde571c1ee 100644 --- a/.github/config/components.yml +++ b/.github/config/components.yml @@ -207,7 +207,7 @@ components: - "ci-infrastructure" # CI changes trigger full regression paths: - "foreign/php/**" - tasks: ["build", "test"] + tasks: ["lint", "test", "build"] sdk-node: depends_on: diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 3215ee9936..61297f589a 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -43,6 +43,7 @@ jobs: (inputs.task == 'build-aarch64-gnu' || inputs.task == 'build-aarch64-musl') && 'ubuntu-24.04-arm' || inputs.task == 'build-macos-aarch64' && 'macos-14' || inputs.task == 'build-windows-sdk' && 'windows-latest' || + inputs.component == 'sdk-php' && 'ubuntu-24.04' || 'ubuntu-latest' }} timeout-minutes: 60 @@ -98,21 +99,11 @@ jobs: override_pr: ${{ github.event.pull_request.number }} # PHP SDK - - name: Set up Docker Buildx for PHP - if: inputs.component == 'sdk-php' - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - name: Run PHP SDK task if: inputs.component == 'sdk-php' - run: | - if [ "${{ inputs.task }}" = "build" ]; then - docker compose -f foreign/php/docker-compose.test.yml build php-tests - elif [ "${{ inputs.task }}" = "test" ]; then - docker compose -f foreign/php/docker-compose.test.yml up --build --abort-on-container-exit --exit-code-from php-tests - else - echo "Unknown PHP SDK task: ${{ inputs.task }}" - exit 1 - fi + uses: ./.github/actions/php/pre-merge + with: + task: ${{ inputs.task }} # Node SDK - name: Run Node SDK task diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml index 25a88bcbb8..9d88a5083e 100644 --- a/.github/workflows/pre-merge.yml +++ b/.github/workflows/pre-merge.yml @@ -285,6 +285,7 @@ jobs: // Set outputs for each component const rust = findJobInfo('Rust •'); const python = findJobInfo('Python •'); + const php = findJobInfo('PHP •'); const node = findJobInfo('Node •'); const go = findJobInfo('Go •'); const java = findJobInfo('Java •'); @@ -305,6 +306,7 @@ jobs: // Output formatted durations core.setOutput('rust_time', formatJobDuration(rust)); core.setOutput('python_time', formatJobDuration(python)); + core.setOutput('php_time', formatJobDuration(php)); core.setOutput('node_time', formatJobDuration(node)); core.setOutput('go_time', formatJobDuration(go)); core.setOutput('java_time', formatJobDuration(java)); @@ -395,6 +397,7 @@ jobs: # Language/component tests rust_status=$(format_status "${{ needs.test-rust.result }}" "${{ steps.times.outputs.rust_time }}") python_status=$(format_status "${{ needs.test-python.result }}" "${{ steps.times.outputs.python_time }}") + php_status=$(format_status "${{ needs.test-php.result }}" "${{ steps.times.outputs.php_time }}") node_status=$(format_status "${{ needs.test-node.result }}" "${{ steps.times.outputs.node_time }}") go_status=$(format_status "${{ needs.test-go.result }}" "${{ steps.times.outputs.go_time }}") java_status=$(format_status "${{ needs.test-java.result }}" "${{ steps.times.outputs.java_time }}") @@ -406,6 +409,7 @@ jobs: echo "| 🦀 Rust | $rust_status | ${{ steps.times.outputs.rust_time }} |" >> $GITHUB_STEP_SUMMARY echo "| 🐍 Python | $python_status | ${{ steps.times.outputs.python_time }} |" >> $GITHUB_STEP_SUMMARY + echo "| 🐘 PHP | $php_status | ${{ steps.times.outputs.php_time }} |" >> $GITHUB_STEP_SUMMARY echo "| 🟢 Node | $node_status | ${{ steps.times.outputs.node_time }} |" >> $GITHUB_STEP_SUMMARY echo "| 🐹 Go | $go_status | ${{ steps.times.outputs.go_time }} |" >> $GITHUB_STEP_SUMMARY echo "| ☕ Java | $java_status | ${{ steps.times.outputs.java_time }} |" >> $GITHUB_STEP_SUMMARY @@ -422,6 +426,7 @@ jobs: [[ "${{ needs.detect.result }}" == "failure" ]] || \ [[ "${{ needs.test-rust.result }}" == "failure" ]] || \ [[ "${{ needs.test-python.result }}" == "failure" ]] || \ + [[ "${{ needs.test-php.result }}" == "failure" ]] || \ [[ "${{ needs.test-node.result }}" == "failure" ]] || \ [[ "${{ needs.test-go.result }}" == "failure" ]] || \ [[ "${{ needs.test-java.result }}" == "failure" ]] || \ @@ -437,6 +442,7 @@ jobs: [[ "${{ needs.detect.result }}" == "cancelled" ]] || \ [[ "${{ needs.test-rust.result }}" == "cancelled" ]] || \ [[ "${{ needs.test-python.result }}" == "cancelled" ]] || \ + [[ "${{ needs.test-php.result }}" == "cancelled" ]] || \ [[ "${{ needs.test-node.result }}" == "cancelled" ]] || \ [[ "${{ needs.test-go.result }}" == "cancelled" ]] || \ [[ "${{ needs.test-java.result }}" == "cancelled" ]] || \ diff --git a/foreign/php/.gitignore b/foreign/php/.gitignore index 1edade7b58..c9f5961ccf 100644 --- a/foreign/php/.gitignore +++ b/foreign/php/.gitignore @@ -1,2 +1,4 @@ /target /vendor +Cargo.lock +composer.lock diff --git a/foreign/php/Cargo.lock b/foreign/php/Cargo.lock deleted file mode 100644 index 79c9126bb7..0000000000 --- a/foreign/php/Cargo.lock +++ /dev/null @@ -1,5479 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common 0.1.7", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher 0.4.4", - "cpufeatures 0.2.17", -] - -[[package]] -name = "aes" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd29a732b644c0431c6140f370d097879203d79b80c94a6747ba0872adaef8" -dependencies = [ - "cipher 0.5.1", - "cpubits", - "cpufeatures 0.3.0", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes 0.8.4", - "cipher 0.4.4", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.17", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "aligned-vec" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" -dependencies = [ - "equator", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "asn1-rs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror 2.0.18", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-dropper" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d901072ae4dcdca2201b98beb02d31fb4b6b2472fbd0e870b12ec15b8b35b2d2" -dependencies = [ - "async-dropper-derive", - "async-dropper-simple", - "async-trait", - "futures", - "tokio", -] - -[[package]] -name = "async-dropper-derive" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35cf17a37761f1c88b8e770b5956820fe84c12854165b6f930c604ea186e47e" -dependencies = [ - "async-trait", - "proc-macro2", - "quote", - "syn 2.0.117", - "tokio", -] - -[[package]] -name = "async-dropper-simple" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c4748dfe8cd3d625ec68fc424fa80c134319881185866f9e173af9e5d8add8" -dependencies = [ - "async-scoped", - "async-trait", - "futures", - "rustc_version", - "tokio", -] - -[[package]] -name = "async-lock" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-scoped" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4042078ea593edffc452eef14e99fdb2b120caa4ad9618bcdeabc4a023b98740" -dependencies = [ - "futures", - "pin-project", - "tokio", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "aws-lc-rs" -version = "1.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - -[[package]] -name = "bitflags" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blake3" -version = "1.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "cpufeatures 0.3.0", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-buffer" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" -dependencies = [ - "hybrid-array", - "zeroize", -] - -[[package]] -name = "bon" -version = "3.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" -dependencies = [ - "bon-macros", - "rustversion", -] - -[[package]] -name = "bon-macros" -version = "3.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" -dependencies = [ - "darling 0.23.0", - "ident_case", - "prettyplease", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.117", -] - -[[package]] -name = "borsh" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" -dependencies = [ - "borsh-derive", - "bytes", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "byte-unit" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" -dependencies = [ - "rust_decimal", - "schemars 1.2.1", - "serde", - "utf8-width", -] - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bytecount" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" - -[[package]] -name = "bytemuck" -version = "1.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "bzip2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" -dependencies = [ - "libbz2-rs-sys", -] - -[[package]] -name = "camino" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" -dependencies = [ - "serde_core", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - -[[package]] -name = "cc" -version = "1.2.62" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chacha20" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.1", -] - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common 0.1.7", - "inout 0.1.4", -] - -[[package]] -name = "cipher" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" -dependencies = [ - "crypto-common 0.2.1", - "inout 0.2.2", -] - -[[package]] -name = "clap" -version = "4.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", - "terminal_size", -] - -[[package]] -name = "clap_derive" -version = "4.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "clap_lex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" - -[[package]] -name = "cmake" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" -dependencies = [ - "cc", -] - -[[package]] -name = "cmov" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" - -[[package]] -name = "colorchoice" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "comfy-table" -version = "7.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" -dependencies = [ - "unicode-segmentation", - "unicode-width", -] - -[[package]] -name = "compio" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b84ee96a86948d04388f3a0b8c36b9f0a6b40b3528ac0d65737e53632fb37fe" -dependencies = [ - "compio-buf", - "compio-driver", - "compio-fs", - "compio-io", - "compio-log", - "compio-macros", - "compio-net", - "compio-quic", - "compio-runtime", - "compio-tls", - "compio-ws", -] - -[[package]] -name = "compio-buf" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00d719dbd8c602ab0d25d219cbc6b517008858de7a8d6c51b4dc95aefff4dce" -dependencies = [ - "arrayvec", - "bytes", - "libc", -] - -[[package]] -name = "compio-driver" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d42d98dc890ee4db00c1e68a723391711aab6d67085880d716b72830f7c715" -dependencies = [ - "cfg-if", - "cfg_aliases", - "compio-buf", - "compio-log", - "crossbeam-queue", - "flume", - "futures-util", - "io-uring", - "io_uring_buf_ring", - "libc", - "once_cell", - "paste", - "pin-project-lite", - "polling", - "slab", - "smallvec", - "socket2", - "synchrony", - "thin-cell", - "windows-sys 0.61.2", -] - -[[package]] -name = "compio-fs" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ee36e1acf2cec4835efe9a986c012b2462c5ef53580e4ee84ae6d5a3d8e3b3" -dependencies = [ - "cfg-if", - "cfg_aliases", - "compio-buf", - "compio-driver", - "compio-io", - "compio-runtime", - "libc", - "os_pipe", - "pin-project-lite", - "widestring", - "windows-sys 0.61.2", -] - -[[package]] -name = "compio-io" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637522f28a64fd5f7dcceaa4ddef13fa8d8020025e8c993f7a069e237835580e" -dependencies = [ - "compio-buf", - "futures-util", - "paste", - "synchrony", -] - -[[package]] -name = "compio-log" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4e560213c1996b618da369b7c9109564b41af9033802ae534465c4ee4e132f" -dependencies = [ - "tracing", -] - -[[package]] -name = "compio-macros" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05ed201484967dc70de77a8f7a02b29aaa8e6c81cbea2e75492ee0c8d97766b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "compio-net" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "becd7d40522c885113752a3640cba9f9d347f205b646bb3f8ff3967173a228f2" -dependencies = [ - "cfg-if", - "compio-buf", - "compio-driver", - "compio-io", - "compio-runtime", - "either", - "libc", - "once_cell", - "socket2", - "widestring", - "windows-sys 0.61.2", -] - -[[package]] -name = "compio-quic" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9efdad81b920108b9de57148e1b9d73dc408b6d06a59ee64836dde651cf026" -dependencies = [ - "cfg_aliases", - "compio-buf", - "compio-io", - "compio-log", - "compio-net", - "compio-runtime", - "flume", - "futures-util", - "libc", - "quinn-proto", - "rustc-hash", - "rustls", - "synchrony", - "thiserror 2.0.18", - "windows-sys 0.61.2", -] - -[[package]] -name = "compio-runtime" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c1c71f011bdd9c8f30e97d877b606505ee6d241c7782cfaed172f66acbd9cd" -dependencies = [ - "async-task", - "cfg-if", - "compio-buf", - "compio-driver", - "compio-log", - "core_affinity", - "crossbeam-queue", - "futures-util", - "libc", - "once_cell", - "pin-project-lite", - "scoped-tls", - "slab", - "socket2", - "windows-sys 0.61.2", -] - -[[package]] -name = "compio-tls" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a7056da226af42cda4c83b00a021cce3e1ee5f4cffc8a0ff8801381e618cf1c" -dependencies = [ - "compio-buf", - "compio-io", - "futures-rustls", - "futures-util", - "rustls", -] - -[[package]] -name = "compio-ws" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d45f47c6e64babcaa6b8df1dffced56012e60e58401255e679f428ddbe9fb6" -dependencies = [ - "compio-buf", - "compio-io", - "compio-log", - "compio-net", - "compio-tls", - "tungstenite 0.28.0", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "constant_time_eq" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" - -[[package]] -name = "convert_case" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "convert_case" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core_affinity" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a034b3a7b624016c6e13f5df875747cc25f884156aad2abd12b6c46797971342" -dependencies = [ - "libc", - "num_cpus", - "winapi", -] - -[[package]] -name = "cpubits" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "typenum", -] - -[[package]] -name = "crypto-common" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher 0.4.4", -] - -[[package]] -name = "ctutils" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" -dependencies = [ - "cmov", -] - -[[package]] -name = "darling" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" -dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", -] - -[[package]] -name = "darling" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" -dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", -] - -[[package]] -name = "darling_core" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "darling_core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" -dependencies = [ - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.117", -] - -[[package]] -name = "darling_macro" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" -dependencies = [ - "darling_core 0.21.3", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "darling_macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" -dependencies = [ - "darling_core 0.23.0", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "data-encoding" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" - -[[package]] -name = "deflate64" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" - -[[package]] -name = "der" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" -dependencies = [ - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "deranged" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", - "serde_core", -] - -[[package]] -name = "derive_more" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "convert_case 0.10.0", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.117", - "unicode-xid", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "crypto-common 0.1.7", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer 0.12.0", - "const-oid", - "crypto-common 0.2.1", - "ctutils", - "zeroize", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "enumset" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f96a4a12fe60ac746ae295a1a4ecb5bb02debc20856506c8635288065f142de" -dependencies = [ - "enumset_derive", -] - -[[package]] -name = "enumset_derive" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" -dependencies = [ - "darling 0.21.3", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "equator" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" -dependencies = [ - "equator-macro", -] - -[[package]] -name = "equator-macro" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "err_trail" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0364ccf1c57e1e4e22f47418b0197163424aa97037b07fc3626a855d94549503" -dependencies = [ - "tracing", -] - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "ext-php-rs" -version = "0.15.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ba219f32e80a5ab8b2562b873f15aeac8028aff1fb1a898409b2e251bfe59d" -dependencies = [ - "anyhow", - "bitflags", - "cc", - "cfg-if", - "ext-php-rs-bindgen", - "ext-php-rs-build", - "ext-php-rs-derive", - "inventory", - "native-tls", - "once_cell", - "parking_lot", - "skeptic", - "ureq", - "zip", -] - -[[package]] -name = "ext-php-rs-bindgen" -version = "0.72.1-extphprs.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4795dd0976bd7d7d321c49e88e836f8e5b5b2b481e089067e303f2945617458a" -dependencies = [ - "bitflags", - "cexpr", - "ext-php-rs-clang-sys", - "itertools", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.117", -] - -[[package]] -name = "ext-php-rs-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561bce8a6312a6182c078cd987d8d9cb6bf9292a35817cfd009ea0bffa794f5f" -dependencies = [ - "anyhow", -] - -[[package]] -name = "ext-php-rs-clang-sys" -version = "1.8.1-extphprs.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa1ad6e482017d457d57d73691f8bed148a8a6198babe90830310c3308480a61" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "ext-php-rs-derive" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6cb94d5f4c1e9758b6b936ad306dea36a034c125334d9a438fe966a5d596a85" -dependencies = [ - "convert_case 0.11.0", - "darling 0.23.0", - "itertools", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "ext-trait" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5" -dependencies = [ - "ext-trait-proc_macros", -] - -[[package]] -name = "ext-trait-proc_macros" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "extension-traits" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537" -dependencies = [ - "ext-trait", -] - -[[package]] -name = "fastbloom" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" -dependencies = [ - "getrandom 0.3.4", - "libm", - "rand 0.9.4", - "siphasher", -] - -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", - "zlib-rs", -] - -[[package]] -name = "flume" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" -dependencies = [ - "fastrand", - "futures-core", - "futures-sink", - "spin", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "futures-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" -dependencies = [ - "futures-io", - "rustls", - "rustls-pki-types", -] - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "generator" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" -dependencies = [ - "cc", - "cfg-if", - "libc", - "log", - "rustversion", - "windows-link", - "windows-result", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi 5.3.0", - "wasip2", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi 6.0.0", - "rand_core 0.10.1", - "wasip2", - "wasip3", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" -dependencies = [ - "digest 0.11.3", -] - -[[package]] -name = "http" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "human-repr" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58b778a5761513caf593693f8951c97a5b610841e754788400f32102eefdff1" - -[[package]] -name = "humantime" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" - -[[package]] -name = "hybrid-array" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" -dependencies = [ - "typenum", -] - -[[package]] -name = "hyper" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "iggy" -version = "0.10.0" -dependencies = [ - "async-broadcast", - "async-dropper", - "async-trait", - "bon", - "bytes", - "dashmap", - "flume", - "futures", - "futures-util", - "iggy_common", - "quinn", - "reqwest", - "reqwest-middleware", - "reqwest-retry", - "reqwest-tracing", - "rustls", - "secrecy", - "serde", - "tokio", - "tokio-rustls", - "tokio-tungstenite", - "tracing", - "trait-variant", - "webpki-roots 1.0.7", -] - -[[package]] -name = "iggy-php" -version = "0.1.0" -dependencies = [ - "bytes", - "ext-php-rs", - "futures", - "iggy", - "php-tokio", - "tokio", -] - -[[package]] -name = "iggy_binary_protocol" -version = "0.10.0" -dependencies = [ - "aligned-vec", - "bytemuck", - "bytes", - "compio-buf", - "enumset", - "secrecy", - "smallvec", - "thiserror 2.0.18", -] - -[[package]] -name = "iggy_common" -version = "0.10.0" -dependencies = [ - "aes-gcm", - "aligned-vec", - "async-broadcast", - "async-trait", - "base64", - "blake3", - "bon", - "byte-unit", - "bytemuck", - "bytes", - "chrono", - "clap", - "comfy-table", - "compio", - "crossbeam", - "derive_more", - "err_trail", - "human-repr", - "humantime", - "iggy_binary_protocol", - "lending-iterator", - "moka", - "nix", - "once_cell", - "papaya", - "rcgen", - "ring", - "rustls", - "secrecy", - "serde", - "serde_json", - "serde_with", - "strum", - "thiserror 2.0.18", - "tokio", - "tracing", - "tungstenite 0.29.0", - "twox-hash", - "ulid", - "uuid", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown 0.17.1", - "serde", - "serde_core", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "generic-array", -] - -[[package]] -name = "inout" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "inventory" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" -dependencies = [ - "rustversion", -] - -[[package]] -name = "io-uring" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d09b98f7eace8982db770e4408e7470b028ce513ac28fecdc6bf4c30fe92b62" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - -[[package]] -name = "io_uring_buf_ring" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1838759bb8c2f24cf05a35429d83145c4aa6af43f8ad38477295e12a7320a80e" -dependencies = [ - "bytes", - "io-uring", - "rustix", -] - -[[package]] -name = "ipnet" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys 0.3.1", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" -dependencies = [ - "cfg-if", - "combine", - "jni-macros", - "jni-sys 0.4.1", - "log", - "simd_cesu8", - "thiserror 2.0.18", - "walkdir", - "windows-link", -] - -[[package]] -name = "jni-macros" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" -dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "simd_cesu8", - "syn 2.0.117", -] - -[[package]] -name = "jni-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" -dependencies = [ - "jni-sys 0.4.1", -] - -[[package]] -name = "jni-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" -dependencies = [ - "jni-sys-macros", -] - -[[package]] -name = "jni-sys-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" -dependencies = [ - "quote", - "syn 2.0.117", -] - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" -dependencies = [ - "cfg-if", - "futures-util", - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "lending-iterator" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc07588c853b50689205fb5c00498aa681d89828e0ce8cbd965ebc7a5d8ae260" -dependencies = [ - "extension-traits", - "lending-iterator-proc_macros", - "macro_rules_attribute", - "never-say-never", - "nougat", - "polonius-the-crab", -] - -[[package]] -name = "lending-iterator-proc_macros" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5445dd1c0deb1e97b8a16561d17fc686ca83e8411128fb036e9668a72d51b1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "libbz2-rs-sys" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a6a8c165077efc8f3a971534c50ea6a1a18b329ef4a66e897a7e3a1494565f" - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "pin-utils", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "lzma-rust2" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47bb1e988e6fb779cf720ad431242d3f03167c1b3f2b1aae7f1a94b2495b36ae" -dependencies = [ - "sha2", -] - -[[package]] -name = "macro_rules_attribute" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862" -dependencies = [ - "macro_rules_attribute-proc_macro", - "paste", -] - -[[package]] -name = "macro_rules_attribute-proc_macro" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d" - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matchit" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f926ade0c4e170215ae43342bf13b9310a437609c81f29f86c5df6657582ef9" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "moka" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" -dependencies = [ - "async-lock", - "crossbeam-channel", - "crossbeam-epoch", - "crossbeam-utils", - "equivalent", - "event-listener", - "futures-util", - "parking_lot", - "portable-atomic", - "smallvec", - "tagptr", - "uuid", -] - -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "never-say-never" -version = "6.6.666" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5a574dadd7941adeaa71823ecba5e28331b8313fb2e1c6a5c7e5981ea53ad6" - -[[package]] -name = "nix" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nougat" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b57b9ced431322f054fc673f1d3c7fa52d80efd9df74ad2fc759f044742510" -dependencies = [ - "macro_rules_attribute", - "nougat-proc_macros", -] - -[[package]] -name = "nougat-proc_macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84f77a45e99a2f9b492695d99e1c23844619caa5f3e57647cffacad773ca257" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-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-conv" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "oid-registry" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" -dependencies = [ - "asn1-rs", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "openssl" -version = "0.10.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0b434746ee2832f4f0baf10137e1cabb18cbe6912c69e2e33263c45250f542" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "openssl-sys" -version = "0.9.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158fe5b292746440aa6e7a7e690e55aeb72d41505e2804c23c6973ad0e9c9781" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "os_pipe" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "papaya" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "997ee03cd38c01469a7046643714f0ad28880bcb9e6679ff0666e24817ca19b7" -dependencies = [ - "equivalent", - "seize", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pbkdf2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" -dependencies = [ - "digest 0.11.3", - "hmac", -] - -[[package]] -name = "pem" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" -dependencies = [ - "base64", - "serde_core", -] - -[[package]] -name = "pem-rfc7468" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "php-tokio" -version = "0.1.7" -source = "git+https://github.com/danog/php-tokio.git?tag=0.1.11#006da31b54346a5f485c914f513871c30482cf2a" -dependencies = [ - "ext-php-rs", - "lazy_static", - "libc", - "php-tokio-derive", - "tokio", - "tokio-pipe", -] - -[[package]] -name = "php-tokio-derive" -version = "0.2.0" -source = "git+https://github.com/danog/php-tokio.git?tag=0.1.11#006da31b54346a5f485c914f513871c30482cf2a" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "pin-project" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf0d9e68100b3a7989b4901972f265cd542e560a3a8a724e1e20322f4d06ce9" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a990e22f43e84855daf260dded30524ef4a9021cc7541c26540500a50b624389" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" - -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "polonius-the-crab" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a69ee997a6282f8462abf1e0d8c38c965e968799e912b3bed8c9e8a28c2f9f" - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppmd-rust" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efca4c95a19a79d1c98f791f10aebd5c1363b473244630bb7dbde1dc98455a24" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - -[[package]] -name = "proc-macro-crate" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "aws-lc-rs", - "bytes", - "fastbloom", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.4", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "rustls-platform-verifier 0.6.2", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.60.2", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" -dependencies = [ - "chacha20", - "getrandom 0.4.2", - "rand_core 0.10.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - -[[package]] -name = "rcgen" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b99e0098aa4082912d4c649628623db6aba77335e4f4569ff5083a6448b32e" -dependencies = [ - "pem", - "ring", - "rustls-pki-types", - "time", - "x509-parser", - "yasna", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "ref-cast" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "reqwest" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" -dependencies = [ - "base64", - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "rustls-platform-verifier 0.7.0", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "reqwest-middleware" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199dda04a536b532d0cc04d7979e39b1c763ea749bf91507017069c00b96056f" -dependencies = [ - "anyhow", - "async-trait", - "http", - "reqwest", - "serde", - "thiserror 2.0.18", - "tower-service", -] - -[[package]] -name = "reqwest-retry" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe2412db2af7d2268e7a5406be0431f37d9eb67ff390f35b395716f5f06c2eaa" -dependencies = [ - "anyhow", - "async-trait", - "futures", - "getrandom 0.2.17", - "http", - "hyper", - "reqwest", - "reqwest-middleware", - "retry-policies", - "thiserror 2.0.18", - "tokio", - "tracing", - "wasmtimer", -] - -[[package]] -name = "reqwest-tracing" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5c1a1510677d43dce9e9c0c07fc5db8772c0e5a43e4f9cef75a11affa05a578" -dependencies = [ - "anyhow", - "async-trait", - "getrandom 0.2.17", - "http", - "matchit", - "reqwest", - "reqwest-middleware", - "tracing", -] - -[[package]] -name = "retry-policies" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc05fbf560421a0357a750cbe78c7ca19d4923918490daabba313d5dbc871e47" -dependencies = [ - "rand 0.10.1", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rkyv" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rust_decimal" -version = "1.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c5108e3d4d903e21aac27f12ba5377b6b34f9f44b325e4894c7924169d06995" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand 0.8.6", - "rkyv", - "serde", - "serde_json", - "wasm-bindgen", -] - -[[package]] -name = "rustc-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.23.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" -dependencies = [ - "aws-lc-rs", - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" -dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni 0.21.1", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" -dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni 0.22.4", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[package]] -name = "rustls-webpki" -version = "0.103.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "secrecy" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" -dependencies = [ - "serde", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "seize" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" -dependencies = [ - "serde", - "serde_core", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" -dependencies = [ - "base64", - "bs58", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.14.0", - "schemars 0.9.0", - "schemars 1.2.1", - "serde_core", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" -dependencies = [ - "darling 0.23.0", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[package]] -name = "sha1" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - -[[package]] -name = "simd_cesu8" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" -dependencies = [ - "rustc_version", - "simdutf8", -] - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "siphasher" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" - -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synchrony" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416090a4d8f6358526df5f9f65dfe28750b8b7bfd1fd8a5620f483fc4a75722c" -dependencies = [ - "futures-util", - "loom", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tagptr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "terminal_size" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" -dependencies = [ - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "thin-cell" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4164c6c316ba9733b0ab021e7f9852c788a4b991b49c25820f1be48e1d41345b" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl 2.0.18", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "time" -version = "0.3.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" -dependencies = [ - "deranged", - "itoa", - "js-sys", - "num-conv", - "powerfmt", - "serde_core", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - -[[package]] -name = "time-macros" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tokio-pipe" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f213a84bffbd61b8fa0ba8a044b4bbe35d471d0b518867181e82bd5c15542784" -dependencies = [ - "libc", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" -dependencies = [ - "futures-util", - "log", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tungstenite 0.29.0", - "webpki-roots 0.26.11", -] - -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.25.11+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" -dependencies = [ - "indexmap 2.14.0", - "toml_datetime", - "toml_parser", - "winnow", -] - -[[package]] -name = "toml_parser" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" -dependencies = [ - "winnow", -] - -[[package]] -name = "tower" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", - "url", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.9.4", - "rustls", - "rustls-pki-types", - "sha1 0.10.6", - "thiserror 2.0.18", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.9.4", - "rustls", - "rustls-pki-types", - "sha1 0.10.6", - "thiserror 2.0.18", -] - -[[package]] -name = "twox-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" -dependencies = [ - "rand 0.9.4", -] - -[[package]] -name = "typed-path" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[package]] -name = "ulid" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" -dependencies = [ - "rand 0.9.4", - "web-time", -] - -[[package]] -name = "unicase" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-segmentation" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common 0.1.7", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "ureq" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" -dependencies = [ - "base64", - "der", - "flate2", - "log", - "native-tls", - "percent-encoding", - "rustls-pki-types", - "ureq-proto", - "utf8-zero", - "webpki-root-certs", -] - -[[package]] -name = "ureq-proto" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" -dependencies = [ - "base64", - "http", - "httparse", - "log", -] - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" - -[[package]] -name = "utf8-zero" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" -dependencies = [ - "getrandom 0.4.2", - "js-sys", - "rand 0.10.1", - "serde_core", - "wasm-bindgen", - "zerocopy", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen 0.51.0", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.117", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.121" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.14.0", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap 2.14.0", - "semver", -] - -[[package]] -name = "wasmtimer" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" -dependencies = [ - "futures", - "js-sys", - "parking_lot", - "pin-utils", - "slab", - "wasm-bindgen", -] - -[[package]] -name = "web-sys" -version = "0.3.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-root-certs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.7", -] - -[[package]] -name = "webpki-roots" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "widestring" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "winnow" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" -dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap 2.14.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap 2.14.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.14.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "x509-parser" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" -dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "ring", - "rusticata-macros", - "thiserror 2.0.18", - "time", -] - -[[package]] -name = "yasna" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" -dependencies = [ - "time", -] - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zip" -version = "8.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" -dependencies = [ - "aes 0.9.0", - "bzip2", - "constant_time_eq", - "crc32fast", - "deflate64", - "flate2", - "getrandom 0.4.2", - "hmac", - "indexmap 2.14.0", - "lzma-rust2", - "memchr", - "pbkdf2", - "ppmd-rust", - "sha1 0.11.0", - "time", - "typed-path", - "zeroize", - "zopfli", - "zstd", -] - -[[package]] -name = "zlib-rs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zopfli" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] - -[[package]] -name = "zstd" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.16+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/foreign/php/Cargo.toml b/foreign/php/Cargo.toml index fea889679e..e10be21771 100644 --- a/foreign/php/Cargo.toml +++ b/foreign/php/Cargo.toml @@ -33,7 +33,6 @@ bytes = "1.11.1" futures = "0.3.32" ext-php-rs = "0.15.13" iggy = { path = "../../core/sdk", version = "0.10.0" } -php-tokio = { git = "https://github.com/danog/php-tokio.git", tag = "0.1.11" } tokio = "1.50.0" [profile.release] diff --git a/foreign/php/Dockerfile.test b/foreign/php/Dockerfile.test index e927efdf47..f2e3f92741 100644 --- a/foreign/php/Dockerfile.test +++ b/foreign/php/Dockerfile.test @@ -19,7 +19,6 @@ FROM rust:1.95-slim-bookworm RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ - composer \ curl \ git \ clang \ @@ -41,8 +40,8 @@ WORKDIR /workspace COPY Cargo.toml Cargo.lock ./ COPY core/ ./core/ -COPY foreign/php/Cargo.toml foreign/php/Cargo.lock ./foreign/php/ -COPY foreign/php/composer.json foreign/php/composer.lock ./foreign/php/ +COPY foreign/php/Cargo.toml ./foreign/php/ +COPY foreign/php/composer.json ./foreign/php/ COPY foreign/php/README.md foreign/php/LICENSE foreign/php/NOTICE ./foreign/php/ COPY foreign/php/.cargo/ ./foreign/php/.cargo/ COPY foreign/php/src/ ./foreign/php/src/ @@ -51,7 +50,6 @@ COPY foreign/php/scripts/ ./foreign/php/scripts/ WORKDIR /workspace/foreign/php -RUN composer install --no-interaction --no-progress --prefer-dist RUN cargo install cargo-php --locked RUN cargo php install --release --yes RUN chmod +x ./scripts/test.sh diff --git a/foreign/php/README.md b/foreign/php/README.md index aabba19d1f..e9de15c932 100644 --- a/foreign/php/README.md +++ b/foreign/php/README.md @@ -3,18 +3,14 @@ PHP extension bindings for [Apache Iggy](https://iggy.apache.org/), built in Rust with [`ext-php-rs`](https://github.com/davidcole1340/ext-php-rs). -This repository is experimental. The extension exposes two PHP clients over the Rust -Iggy client: - -- `IggyClient`: blocking, synchronous PHP API. -- `IggyAsyncClient`: Fiber/Revolt-aware API powered by `php-tokio`. +This repository is experimental. The extension exposes `IggyClient`, a blocking +synchronous PHP API over the Rust Iggy client. ## Requirements - Rust and Cargo - PHP with `php-config` - `cargo-php` -- Composer, for async test dependencies - Docker, for running the integration test server On macOS with Homebrew PHP: @@ -70,8 +66,6 @@ Override them with `IGGY_HOST`, `IGGY_PORT`, `IGGY_USERNAME`, and `IGGY_PASSWORD ## Usage -### Synchronous Client - ```php IggyAsyncClient::wakeup(), -); - -try { - $future = async(function () { - $client = new IggyAsyncClient('127.0.0.1:8090'); - $client->connect(); - $client->loginUser('iggy', 'iggy'); - $client->ping(); - - return 'pong'; - }); - - echo $future->await(), PHP_EOL; -} finally { - EventLoop::cancel($watcher); - fclose($readable); - IggyAsyncClient::shutdown(); -} -``` - -The async client covers the core connection, stream, topic, send, poll, and -consumer-group operations. `IggyAsyncConsumer::iterMessages()->next()` and -`IggyAsyncConsumer::consumeMessages()` suspend the current Fiber while waiting for -messages. - ## Tests Run the Dockerized integration suite: @@ -173,13 +112,6 @@ Run the PHP test suite: php tests/run.php ``` -Async tests require Composer dependencies: - -```sh -composer install -php tests/run.php IggyAsyncSdkTest -``` - Run Rust verification: ```sh @@ -198,5 +130,3 @@ setup. Set `IGGY_TLS_CONNECTION_STRING` to enable TLS connection tests. Set - Large unsigned values that can overflow PHP integers, such as message checksums, are returned as decimal strings. - `IggyClient` is synchronous and blocks the current PHP thread. -- `IggyAsyncClient` is Fiber/Revolt-aware. Its methods must be called after - `IggyAsyncClient::init()` and from a Fiber-aware runtime such as Amp/Revolt. diff --git a/foreign/php/composer.json b/foreign/php/composer.json index 461f951882..4b7b1a7bb7 100644 --- a/foreign/php/composer.json +++ b/foreign/php/composer.json @@ -3,10 +3,6 @@ "description": "PHP extension bindings for Apache Iggy.", "license": "Apache-2.0", "type": "library", - "require-dev": { - "amphp/amp": "^3.0", - "revolt/event-loop": "^1.0" - }, "scripts": { "test": "php tests/run.php" } diff --git a/foreign/php/composer.lock b/foreign/php/composer.lock deleted file mode 100644 index b2f220982c..0000000000 --- a/foreign/php/composer.lock +++ /dev/null @@ -1,172 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "3842dabaa05a2bd5fbaa193d589fc790", - "packages": [], - "packages-dev": [ - { - "name": "amphp/amp", - "version": "v3.1.1", - "source": { - "type": "git", - "url": "https://github.com/amphp/amp.git", - "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", - "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^9", - "psalm/phar": "5.23.1" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php", - "src/Future/functions.php", - "src/Internal/functions.php" - ], - "psr-4": { - "Amp\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - } - ], - "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "https://amphp.org/amp", - "keywords": [ - "async", - "asynchronous", - "awaitable", - "concurrency", - "event", - "event-loop", - "future", - "non-blocking", - "promise" - ], - "support": { - "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.1.1" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-08-27T21:42:00+00:00" - }, - { - "name": "revolt/event-loop", - "version": "v1.0.8", - "source": { - "type": "git", - "url": "https://github.com/revoltphp/event-loop.git", - "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/b6fc06dce8e9b523c9946138fa5e62181934f91c", - "reference": "b6fc06dce8e9b523c9946138fa5e62181934f91c", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "ext-json": "*", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.15" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Revolt\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - }, - { - "name": "Christian Lück", - "email": "christian@clue.engineering" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "Rock-solid event loop for concurrent PHP applications.", - "keywords": [ - "async", - "asynchronous", - "concurrency", - "event", - "event-loop", - "non-blocking", - "scheduler" - ], - "support": { - "issues": "https://github.com/revoltphp/event-loop/issues", - "source": "https://github.com/revoltphp/event-loop/tree/v1.0.8" - }, - "time": "2025-08-27T21:33:23+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": {}, - "prefer-stable": false, - "prefer-lowest": false, - "platform": {}, - "platform-dev": {}, - "plugin-api-version": "2.9.0" -} diff --git a/foreign/php/scripts/test.sh b/foreign/php/scripts/test.sh index 626738a3fb..6bbcf6798c 100755 --- a/foreign/php/scripts/test.sh +++ b/foreign/php/scripts/test.sh @@ -35,4 +35,10 @@ echo "Server is ready." mkdir -p test-results -php tests/run.php "$@" +PHP_BIN="${PHP:-php}" +PHP_ARGS=() +if [ -n "${IGGY_PHP_EXTENSION:-}" ]; then + PHP_ARGS+=("-d" "extension=${IGGY_PHP_EXTENSION}") +fi + +"${PHP_BIN}" "${PHP_ARGS[@]}" tests/run.php "$@" diff --git a/foreign/php/src/async_client.rs b/foreign/php/src/async_client.rs deleted file mode 100644 index 58facbb589..0000000000 --- a/foreign/php/src/async_client.rs +++ /dev/null @@ -1,376 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -use std::{str::FromStr, sync::Arc, time::Duration}; - -use ext_php_rs::{ - exception::{PhpException, PhpResult}, - php_class, php_impl, -}; -use iggy::prelude::{ - CompressionAlgorithm, Consumer as RustConsumer, Identifier, IggyClient as RustIggyClient, - IggyClientBuilder, IggyDuration, IggyExpiry, IggyMessage as RustMessage, MaxTopicSize, - Partitioning, PollingStrategy as RustPollingStrategy, *, -}; -use php_tokio::EventLoop; -use tokio::sync::Mutex; - -use crate::async_consumer::IggyAsyncConsumer; -use crate::consumer::AutoCommit; -use crate::identifier::PhpIdentifier; -use crate::receive_message::{PollingStrategy, ReceiveMessage}; -use crate::send_message::SendMessage; -use crate::stream::StreamDetails; -use crate::topic::TopicDetails; - -type AsyncPhpResult = Result; - -/// A Fiber/Revolt-aware PHP client for Iggy. -/// -/// Methods suspend the current PHP Fiber while the Rust Tokio future is pending. -/// Use `IggyAsyncClient::init()` and `IggyAsyncClient::wakeup()` to bridge Tokio -/// readiness notifications into the PHP event loop. -#[php_class] -pub struct IggyAsyncClient { - inner: Arc, -} - -#[php_impl] -impl IggyAsyncClient { - /// Constructs a new async client from a TCP server address. - #[php(constructor)] - pub fn __construct(conn: Option) -> PhpResult { - let client = IggyClientBuilder::new() - .with_tcp() - .with_server_address(conn.unwrap_or_else(|| "127.0.0.1:8090".to_string())) - .build() - .map_err(to_php_exception)?; - - Ok(Self { - inner: Arc::new(client), - }) - } - - /// Initializes the php-tokio bridge and returns a readable file descriptor. - /// - /// Register this descriptor with Revolt and call `IggyAsyncClient::wakeup()` - /// whenever it becomes readable. - pub fn init() -> PhpResult { - EventLoop::init() - } - - /// Resumes PHP Fibers whose Tokio futures have completed. - pub fn wakeup() -> PhpResult { - EventLoop::wakeup() - } - - /// Clears the thread-local php-tokio bridge state. - pub fn shutdown() { - EventLoop::shutdown(); - } - - /// Constructs a new async client from a connection string. - pub fn from_connection_string(connection_string: String) -> PhpResult { - let client = - RustIggyClient::from_connection_string(&connection_string).map_err(to_php_exception)?; - - Ok(Self { - inner: Arc::new(client), - }) - } - - /// Sends a ping request to the server. - pub fn ping(&self) -> AsyncPhpResult { - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { inner.ping().await.map_err(to_async_exception) }) - } - - /// Logs in the user with the given credentials. - pub fn login_user(&self, username: String, password: String) -> AsyncPhpResult { - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .login_user(&username, &password) - .await - .map(|_| ()) - .map_err(to_async_exception) - }) - } - - /// Connects the client to its service. - pub fn connect(&self) -> AsyncPhpResult { - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { inner.connect().await.map_err(to_async_exception) }) - } - - /// Creates a new stream. - pub fn create_stream(&self, name: String) -> AsyncPhpResult { - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .create_stream(&name) - .await - .map(|_| ()) - .map_err(to_async_exception) - }) - } - - /// Gets a stream by id or name. - pub fn get_stream(&self, stream_id: PhpIdentifier) -> AsyncPhpResult> { - let stream_id = Identifier::from(stream_id); - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .get_stream(&stream_id) - .await - .map(|stream| stream.map(StreamDetails::from)) - .map_err(to_async_exception) - }) - } - - /// Creates a topic. - /// - /// message_expiry_micros is null for server default. - #[allow(clippy::too_many_arguments)] - pub fn create_topic( - &self, - stream: PhpIdentifier, - name: String, - partitions_count: u32, - compression_algorithm: Option, - replication_factor: Option, - message_expiry_micros: Option, - max_topic_size: Option, - ) -> AsyncPhpResult { - let compression_algorithm = match compression_algorithm { - Some(value) => CompressionAlgorithm::from_str(&value).map_err(to_async_exception)?, - None => CompressionAlgorithm::default(), - }; - let expiry = message_expiry_micros.map_or(IggyExpiry::ServerDefault, |micros| { - IggyExpiry::ExpireDuration(iggy_duration_from_micros(micros)) - }); - let max_size = max_topic_size.map_or(MaxTopicSize::ServerDefault, MaxTopicSize::from); - let stream = Identifier::from(stream); - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .create_topic( - &stream, - &name, - partitions_count, - compression_algorithm, - replication_factor, - expiry, - max_size, - ) - .await - .map(|_| ()) - .map_err(to_async_exception) - }) - } - - /// Gets a topic by stream and topic id/name. - pub fn get_topic( - &self, - stream_id: PhpIdentifier, - topic_id: PhpIdentifier, - ) -> AsyncPhpResult> { - let stream_id = Identifier::from(stream_id); - let topic_id = Identifier::from(topic_id); - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .get_topic(&stream_id, &topic_id) - .await - .map(|topic| topic.map(TopicDetails::from)) - .map_err(to_async_exception) - }) - } - - /// Sends messages to a topic. - pub fn send_messages( - &self, - stream: PhpIdentifier, - topic: PhpIdentifier, - partition_id: u32, - messages: Vec<&SendMessage>, - ) -> AsyncPhpResult { - let stream = Identifier::from(stream); - let topic = Identifier::from(topic); - let partitioning = Partitioning::partition_id(partition_id); - let mut messages: Vec = messages - .into_iter() - .map(|message| (*message).clone().inner) - .collect(); - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .send_messages(&stream, &topic, &partitioning, messages.as_mut()) - .await - .map_err(to_async_exception) - }) - } - - /// Polls messages from the specified topic and partition. - pub fn poll_messages( - &self, - stream: PhpIdentifier, - topic: PhpIdentifier, - partition_id: u32, - polling_strategy: &PollingStrategy, - count: u32, - auto_commit: bool, - ) -> AsyncPhpResult> { - let consumer = RustConsumer::default(); - let stream = Identifier::from(stream); - let topic = Identifier::from(topic); - let strategy: RustPollingStrategy = polling_strategy.into(); - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - let polled_messages = inner - .poll_messages( - &stream, - &topic, - Some(partition_id), - &consumer, - &strategy, - count, - auto_commit, - ) - .await - .map_err(to_async_exception)?; - - Ok(polled_messages - .messages - .into_iter() - .map(|message| ReceiveMessage { - inner: message, - partition_id, - }) - .collect()) - }) - } - - /// Creates and initializes a consumer group consumer. - #[allow(clippy::too_many_arguments)] - pub fn consumer_group( - &self, - name: String, - stream: String, - topic: String, - partition_id: Option, - polling_strategy: Option<&PollingStrategy>, - batch_length: Option, - auto_commit: Option<&AutoCommit>, - create_consumer_group_if_not_exists: bool, - auto_join_consumer_group: bool, - poll_interval_micros: Option, - polling_retry_interval_micros: Option, - init_retries: Option, - init_retry_interval_micros: Option, - allow_replay: bool, - ) -> AsyncPhpResult { - let mut builder = self - .inner - .consumer_group(&name, &stream, &topic) - .map_err(to_async_exception)? - .without_encryptor() - .partition(partition_id); - - builder = if create_consumer_group_if_not_exists { - builder.create_consumer_group_if_not_exists() - } else { - builder.do_not_create_consumer_group_if_not_exists() - }; - builder = if auto_join_consumer_group { - builder.auto_join_consumer_group() - } else { - builder.do_not_auto_join_consumer_group() - }; - if let Some(polling_strategy) = polling_strategy { - builder = builder.polling_strategy(polling_strategy.into()); - } - if let Some(batch_length) = batch_length { - builder = builder.batch_length(batch_length); - } - if let Some(auto_commit) = auto_commit { - builder = builder.auto_commit(auto_commit.into()); - } - builder = match poll_interval_micros { - Some(micros) => builder.poll_interval(iggy_duration_from_micros(micros)), - None => builder.without_poll_interval(), - }; - if let Some(micros) = polling_retry_interval_micros { - builder = builder.polling_retry_interval(iggy_duration_from_micros(micros)); - } - - match (init_retries, init_retry_interval_micros) { - (Some(retries), Some(micros)) => { - builder = builder.init_retries(retries, iggy_duration_from_micros(micros)); - } - (Some(_), None) => { - return Err( - "'init_retry_interval_micros' is required if 'init_retries' is set".to_string(), - ); - } - (None, Some(_)) => { - return Err( - "'init_retries' is required if 'init_retry_interval_micros' is set".to_string(), - ); - } - (None, None) => {} - } - if allow_replay { - builder = builder.allow_replay(); - } - - let mut consumer = builder.build(); - EventLoop::suspend_on(async move { - consumer.init().await.map_err(to_async_exception)?; - Ok(IggyAsyncConsumer { - inner: Arc::new(Mutex::new(consumer)), - }) - }) - } -} - -pub unsafe extern "C" fn request_shutdown(_type: i32, _module_number: i32) -> i32 { - EventLoop::shutdown(); - 0 -} - -fn to_php_exception(error: impl std::fmt::Display) -> PhpException { - PhpException::default(error.to_string()) -} - -fn to_async_exception(error: impl std::fmt::Display) -> String { - error.to_string() -} - -fn iggy_duration_from_micros(micros: u64) -> IggyDuration { - IggyDuration::new(Duration::from_micros(micros)) -} diff --git a/foreign/php/src/async_consumer.rs b/foreign/php/src/async_consumer.rs deleted file mode 100644 index f516b63831..0000000000 --- a/foreign/php/src/async_consumer.rs +++ /dev/null @@ -1,166 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -use std::sync::Arc; - -use ext_php_rs::{php_class, php_impl, types::ZendCallable}; -use futures::StreamExt; -use iggy::prelude::IggyConsumer as RustIggyConsumer; -use php_tokio::EventLoop; -use tokio::sync::Mutex; - -use crate::receive_message::ReceiveMessage; - -type AsyncPhpResult = Result; - -#[php_class] -pub struct IggyAsyncConsumer { - pub(crate) inner: Arc>, -} - -#[php_impl] -impl IggyAsyncConsumer { - /// Get the last consumed offset or null if no offset has been consumed yet. - pub fn get_last_consumed_offset(&self, partition_id: u32) -> Option { - self.inner - .blocking_lock() - .get_last_consumed_offset(partition_id) - } - - /// Get the last stored offset or null if no offset has been stored yet. - pub fn get_last_stored_offset(&self, partition_id: u32) -> Option { - self.inner - .blocking_lock() - .get_last_stored_offset(partition_id) - } - - /// Gets the name of the consumer group. - pub fn name(&self) -> String { - self.inner.blocking_lock().name().to_string() - } - - /// Gets the current partition id or 0 if no messages have been polled yet. - pub fn partition_id(&self) -> u32 { - self.inner.blocking_lock().partition_id() - } - - /// Gets the stream identifier this consumer is configured for. - pub fn stream(&self) -> String { - self.inner.blocking_lock().stream().to_string() - } - - /// Gets the topic identifier this consumer is configured for. - pub fn topic(&self) -> String { - self.inner.blocking_lock().topic().to_string() - } - - /// Stores the provided offset for the provided partition id. - /// - /// If partition_id is null, the current partition id is used. - pub fn store_offset(&self, offset: u64, partition_id: Option) -> AsyncPhpResult { - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .lock() - .await - .store_offset(offset, partition_id) - .await - .map_err(to_async_exception) - }) - } - - /// Deletes the stored offset for the provided partition id. - /// - /// If partition_id is null, the current partition id is used. - pub fn delete_offset(&self, partition_id: Option) -> AsyncPhpResult { - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - inner - .lock() - .await - .delete_offset(partition_id) - .await - .map_err(to_async_exception) - }) - } - - /// Returns an iterator whose next() method suspends until a message is available. - pub fn iter_messages(&self) -> IggyAsyncReceiveMessageIterator { - IggyAsyncReceiveMessageIterator { - inner: self.inner.clone(), - } - } - - /// Consumes messages with a PHP callback. - /// - /// The callback is called as callback(ReceiveMessage $message). If limit is null, - /// this method runs until the consumer stream ends or an error occurs. - pub fn consume_messages( - &self, - callback: ZendCallable, - limit: Option, - ) -> AsyncPhpResult { - let mut consumed = 0; - let max_messages = limit.unwrap_or(u32::MAX); - let iterator = self.iter_messages(); - - while consumed < max_messages { - let Some(message) = iterator.next()? else { - break; - }; - - callback - .try_call(vec![&message]) - .map_err(|err| err.to_string())?; - consumed += 1; - } - - Ok(consumed) - } -} - -#[php_class] -pub struct IggyAsyncReceiveMessageIterator { - pub(crate) inner: Arc>, -} - -#[php_impl] -impl IggyAsyncReceiveMessageIterator { - pub fn next(&self) -> AsyncPhpResult> { - let inner = self.inner.clone(); - - EventLoop::suspend_on(async move { - let mut inner = inner.lock().await; - - match inner.next().await { - Some(Ok(message)) => Ok(Some(ReceiveMessage { - inner: message.message, - partition_id: message.partition_id, - })), - Some(Err(err)) => Err(err.to_string()), - None => Ok(None), - } - }) - } -} - -fn to_async_exception(error: impl std::fmt::Display) -> String { - error.to_string() -} diff --git a/foreign/php/src/lib.rs b/foreign/php/src/lib.rs index ec5283d5e7..79051abd70 100644 --- a/foreign/php/src/lib.rs +++ b/foreign/php/src/lib.rs @@ -16,8 +16,6 @@ * under the License. */ -pub mod async_client; -pub mod async_consumer; pub mod client; pub mod consumer; pub mod identifier; @@ -29,8 +27,6 @@ pub mod topic; use ext_php_rs::prelude::*; -use crate::async_client::IggyAsyncClient; -use crate::async_consumer::{IggyAsyncConsumer, IggyAsyncReceiveMessageIterator}; use crate::client::IggyClient; use crate::consumer::{AutoCommit, AutoCommitAfter, AutoCommitWhen, IggyConsumer}; use crate::iterator::ReceiveMessageIterator; @@ -42,11 +38,7 @@ use crate::topic::TopicDetails; #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module - .request_shutdown_function(crate::async_client::request_shutdown) .class::() - .class::() - .class::() - .class::() .class::() .class::() .class::() diff --git a/foreign/php/tests/IggyAsyncSdkTest.php b/foreign/php/tests/IggyAsyncSdkTest.php deleted file mode 100644 index 519428b94e..0000000000 --- a/foreign/php/tests/IggyAsyncSdkTest.php +++ /dev/null @@ -1,195 +0,0 @@ -connect(); - $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); - $client->ping(); - }); - } - - public function testAsyncSendAndPollMessages(): void - { - run_async(function (): void { - $client = new IggyAsyncClient(server_host() . ':' . server_port()); - $client->connect(); - $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); - - $streamName = unique_name('async-msg-stream'); - $topicName = unique_name('async-msg-topic'); - $partitionId = 0; - $messages = array_map( - static fn (int $i): string => "Async message {$i} - {$streamName}", - range(1, 3), - ); - - create_stream_and_topic($client, $streamName, $topicName); - $client->sendMessages( - $streamName, - $topicName, - $partitionId, - array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), - ); - - $polled = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::first(), 10, true); - assert_true(count($polled) >= count($messages), 'expected at least the sent async messages'); - assert_same($messages, array_slice(collect_payloads($polled), 0, count($messages))); - }); - } - - public function testAsyncConsumerGroupMeta(): void - { - run_async(function (): void { - $client = new IggyAsyncClient(server_host() . ':' . server_port()); - $client->connect(); - $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); - - $consumerName = unique_name('async-consumer-group-consumer'); - $streamName = unique_name('async-consumer-group-stream'); - $topicName = unique_name('async-consumer-group-topic'); - $partitionId = 0; - - create_stream_and_topic($client, $streamName, $topicName); - $consumer = $this->consumerGroup($client, $consumerName, $streamName, $topicName, $partitionId); - - assert_true($consumer instanceof IggyAsyncConsumer); - assert_same($streamName, $consumer->stream()); - assert_same($topicName, $consumer->topic()); - assert_same(0, $consumer->partitionId()); - assert_null($consumer->getLastConsumedOffset($partitionId)); - assert_null($consumer->getLastStoredOffset($partitionId)); - }); - } - - public function testAsyncConsumeMessages(): void - { - run_async(function (): void { - $client = new IggyAsyncClient(server_host() . ':' . server_port()); - $client->connect(); - $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); - - $consumerName = unique_name('async-consumer-group-consumer'); - $streamName = unique_name('async-consumer-group-stream'); - $topicName = unique_name('async-consumer-group-topic'); - $partitionId = 0; - $messages = array_map( - static fn (int $i): string => "Async consumer group test {$i} - {$streamName}", - range(0, 4), - ); - - create_stream_and_topic($client, $streamName, $topicName); - $client->sendMessages( - $streamName, - $topicName, - $partitionId, - array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), - ); - - $consumer = $this->consumerGroup($client, $consumerName, $streamName, $topicName, $partitionId); - $received = []; - $count = $consumer->consumeMessages( - static function (ReceiveMessage $message) use (&$received): void { - $received[] = $message->payload(); - }, - count($messages), - ); - - assert_same(count($messages), $count); - assert_same($messages, $received); - }); - } - - public function testAsyncIterMessages(): void - { - run_async(function (): void { - $client = new IggyAsyncClient(server_host() . ':' . server_port()); - $client->connect(); - $client->loginUser(env_or_default('IGGY_USERNAME', 'iggy'), env_or_default('IGGY_PASSWORD', 'iggy')); - - $consumerName = unique_name('async-consumer-group-consumer'); - $streamName = unique_name('async-consumer-group-stream'); - $topicName = unique_name('async-consumer-group-topic'); - $partitionId = 0; - $messages = array_map( - static fn (int $i): string => "Async iterator test {$i} - {$streamName}", - range(0, 4), - ); - - create_stream_and_topic($client, $streamName, $topicName); - $client->sendMessages( - $streamName, - $topicName, - $partitionId, - array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), - ); - - $consumer = $this->consumerGroup($client, $consumerName, $streamName, $topicName, $partitionId); - $iterator = $consumer->iterMessages(); - assert_true($iterator instanceof IggyAsyncReceiveMessageIterator); - - $received = []; - while (count($received) < count($messages)) { - $message = $iterator->next(); - assert_not_null($message); - $received[] = $message->payload(); - } - - assert_same($messages, $received); - }); - } - - private function consumerGroup( - IggyAsyncClient $client, - string $consumerName, - string $streamName, - string $topicName, - int $partitionId, - ): IggyAsyncConsumer { - return $client->consumerGroup( - $consumerName, - $streamName, - $topicName, - $partitionId, - PollingStrategy::next(), - 10, - AutoCommit::interval(micros(5)), - true, - true, - micros(1), - null, - null, - null, - false, - ); - } -} diff --git a/foreign/php/tests/bootstrap.php b/foreign/php/tests/bootstrap.php index f04ab8c61c..d64c575f63 100644 --- a/foreign/php/tests/bootstrap.php +++ b/foreign/php/tests/bootstrap.php @@ -151,48 +151,3 @@ function micros(int $seconds): int { return $seconds * 1_000_000; } - -function load_async_dependencies(): void -{ - if (class_exists('\\Revolt\\EventLoop') && function_exists('\\Amp\\async')) { - return; - } - - $autoload = dirname(__DIR__) . '/vendor/autoload.php'; - if (!is_file($autoload)) { - throw new SkippedTest('run composer install to install Revolt/Amp async test dependencies'); - } - - require_once $autoload; - - if (!class_exists('\\Revolt\\EventLoop') || !function_exists('\\Amp\\async')) { - throw new SkippedTest('Revolt/Amp async test dependencies are unavailable'); - } -} - -function run_async(callable $callback): mixed -{ - load_async_dependencies(); - - $fd = IggyAsyncClient::init(); - $stream = fopen('php://fd/' . $fd, 'r'); - if ($stream === false) { - throw new TestFailure('failed to open php-tokio readiness fd'); - } - stream_set_blocking($stream, false); - - $watcher = \Revolt\EventLoop::onReadable( - $stream, - static fn (): null => IggyAsyncClient::wakeup(), - ); - - try { - $future = \Amp\async($callback); - - return $future->await(); - } finally { - \Revolt\EventLoop::cancel($watcher); - fclose($stream); - IggyAsyncClient::shutdown(); - } -} diff --git a/foreign/php/tests/run.php b/foreign/php/tests/run.php index a9b644f359..77d1e9b1e3 100644 --- a/foreign/php/tests/run.php +++ b/foreign/php/tests/run.php @@ -22,7 +22,6 @@ declare(strict_types=1); require __DIR__ . '/bootstrap.php'; -require __DIR__ . '/IggyAsyncSdkTest.php'; require __DIR__ . '/IggySdkTest.php'; require __DIR__ . '/TlsTest.php'; @@ -33,7 +32,7 @@ } $filter = $argv[1] ?? null; -$classes = [IggySdkTest::class, IggyAsyncSdkTest::class, TlsTest::class]; +$classes = [IggySdkTest::class, TlsTest::class]; $passed = 0; $skipped = 0; $failed = 0; From 6aabe5312bdfef7d9602124e0265bd7d0df5d9a3 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Tue, 12 May 2026 15:15:33 +0300 Subject: [PATCH 5/7] Keep PHP SDK PR scoped to PHP The Python test compose adjustment was unrelated to the PHP SDK review and made the PR harder to reason about. Restore it to master so this branch only carries the PHP SDK and its CI wiring. Constraint: Review feedback is focused on PHP SDK size and CI validity Rejected: Keep Python compose reachability tweak | unrelated to this PR and should be handled separately if still needed Confidence: high Scope-risk: narrow Directive: Do not mix foreign SDK compose changes into the PHP SDK PR unless they are required by PHP tests Tested: git diff confirmed foreign/python/docker-compose.test.yml matches master Not-tested: Python Docker Compose runtime --- foreign/python/docker-compose.test.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/foreign/python/docker-compose.test.yml b/foreign/python/docker-compose.test.yml index 005857d2ab..92ffec6daf 100644 --- a/foreign/python/docker-compose.test.yml +++ b/foreign/python/docker-compose.test.yml @@ -24,13 +24,7 @@ services: dockerfile: core/server/Dockerfile args: PROFILE: debug - command: ["--fresh", "--with-default-root-credentials"] container_name: iggy-server-python-test - environment: - - IGGY_HTTP_ADDRESS=0.0.0.0:3000 - - IGGY_TCP_ADDRESS=0.0.0.0:8090 - - IGGY_QUIC_ADDRESS=0.0.0.0:8080 - - IGGY_WEBSOCKET_ADDRESS=0.0.0.0:8092 networks: - python-test-network ports: @@ -38,7 +32,7 @@ services: - "8080:8080" - "8090:8090" healthcheck: - test: [ "CMD", "/usr/local/bin/iggy", "--tcp-server-address", "127.0.0.1:8090", "ping" ] + test: [ "CMD", "curl", "-f", "http://localhost:3000/stats" ] interval: 5s timeout: 5s retries: 12 From 64d3315b9a8ad7630839b4a3d5f90e2815a8902f Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Tue, 12 May 2026 16:05:59 +0300 Subject: [PATCH 6/7] Avoid leaking PHP extension path into Iggy config The PHP test action wrote IGGY_PHP_EXTENSION through GITHUB_ENV before starting the Iggy server. Server config validation treats every IGGY_* variable as typed configuration and panicked on the unknown extension path variable, so the PHP test job never reached the test runner. Constraint: Iggy server rejects unknown IGGY_* environment variables Rejected: Add IGGY_PHP_EXTENSION to server ignored vars | the variable is test-runner specific and should not enter server config Confidence: high Scope-risk: narrow Directive: Keep PHP test harness variables outside the IGGY_* namespace unless they are real server configuration Tested: bash -n foreign/php/scripts/test.sh; Ruby YAML parse for .github/actions/php/pre-merge/action.yml Not-tested: Full GitHub Actions rerun --- .github/actions/php/pre-merge/action.yml | 2 +- foreign/php/scripts/test.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/php/pre-merge/action.yml b/.github/actions/php/pre-merge/action.yml index 174a51d013..2c1717e199 100644 --- a/.github/actions/php/pre-merge/action.yml +++ b/.github/actions/php/pre-merge/action.yml @@ -98,7 +98,7 @@ runs: echo "PHP extension was not produced" exit 1 fi - echo "IGGY_PHP_EXTENSION=$(realpath "$extension")" >> "$GITHUB_ENV" + echo "PHP_IGGY_EXTENSION=$(realpath "$extension")" >> "$GITHUB_ENV" ls -lh "$extension" - name: Start Iggy server diff --git a/foreign/php/scripts/test.sh b/foreign/php/scripts/test.sh index 6bbcf6798c..dfa5c5afde 100755 --- a/foreign/php/scripts/test.sh +++ b/foreign/php/scripts/test.sh @@ -37,8 +37,8 @@ mkdir -p test-results PHP_BIN="${PHP:-php}" PHP_ARGS=() -if [ -n "${IGGY_PHP_EXTENSION:-}" ]; then - PHP_ARGS+=("-d" "extension=${IGGY_PHP_EXTENSION}") +if [ -n "${PHP_IGGY_EXTENSION:-}" ]; then + PHP_ARGS+=("-d" "extension=${PHP_IGGY_EXTENSION}") fi "${PHP_BIN}" "${PHP_ARGS[@]}" tests/run.php "$@" From e2e91ed81c88910b81dabe33da37ce179617cd19 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Sat, 16 May 2026 10:14:58 +0300 Subject: [PATCH 7/7] Address PHP adapter review feedback The PHP adapter review surfaced avoidable production panics, duplicated runtime setup, a test harness that bypassed PHPUnit, and an exported iterator wrapper that did not provide native PHP iterator semantics. This keeps the blocking PHP API smaller by using callback consumption, one shared Tokio runtime, fallible identifier conversion, and PHPUnit-backed integration tests. Constraint: PHP adapter remains a synchronous blocking API over async Rust client calls Constraint: composer.lock is intentionally ignored by foreign/php/.gitignore Rejected: Keep ReceiveMessageIterator as a PHP class | it was not a real PHP Iterator and duplicated consumeMessages behavior Rejected: Add new runtime instances per exported class | one shared runtime is simpler and matches the blocking extension boundary Confidence: medium Scope-risk: moderate Directive: Do not reintroduce unwrap-based identifier conversion at PHP boundaries; return PHP exceptions instead Tested: cargo fmt --manifest-path foreign/php/Cargo.toml -- --check Tested: php -l tests/IggySdkTest.php && php -l tests/TlsTest.php && php -l tests/bootstrap.php Tested: composer validate --no-check-publish Tested: composer install --dry-run --no-interaction --prefer-dist Not-tested: cargo check --manifest-path foreign/php/Cargo.toml fails in ext-php-rs 0.15.13 with local Homebrew PHP 8.5 headers before this crate compiles Not-tested: Docker integration image and PHPUnit integration suite because Docker daemon is not running --- foreign/php/Dockerfile.test | 7 ++- foreign/php/README.md | 4 +- foreign/php/composer.json | 5 +- foreign/php/phpunit.xml.dist | 11 ++++ foreign/php/scripts/test.sh | 2 +- foreign/php/src/client.rs | 30 ++++------- foreign/php/src/consumer.rs | 68 ++++++++++++++----------- foreign/php/src/identifier.rs | 34 +++++++++---- foreign/php/src/iterator.rs | 65 ------------------------ foreign/php/src/lib.rs | 4 +- foreign/php/src/receive_message.rs | 4 +- foreign/php/src/runtime.rs | 30 +++++++++++ foreign/php/src/send_message.rs | 19 +++---- foreign/php/tests/IggySdkTest.php | 79 ++--------------------------- foreign/php/tests/TlsTest.php | 15 +++--- foreign/php/tests/bootstrap.php | 33 ++++++------ foreign/php/tests/run.php | 80 ------------------------------ 17 files changed, 162 insertions(+), 328 deletions(-) create mode 100644 foreign/php/phpunit.xml.dist delete mode 100644 foreign/php/src/iterator.rs create mode 100644 foreign/php/src/runtime.rs delete mode 100644 foreign/php/tests/run.php diff --git a/foreign/php/Dockerfile.test b/foreign/php/Dockerfile.test index f2e3f92741..5fb81e91df 100644 --- a/foreign/php/Dockerfile.test +++ b/foreign/php/Dockerfile.test @@ -24,8 +24,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ libclang-dev \ libssl-dev \ + composer \ php-cli \ php-dev \ + php-mbstring \ + php-xml \ pkg-config \ unzip \ && rm -rf /var/lib/apt/lists/* @@ -42,6 +45,7 @@ COPY core/ ./core/ COPY foreign/php/Cargo.toml ./foreign/php/ COPY foreign/php/composer.json ./foreign/php/ +COPY foreign/php/phpunit.xml.dist ./foreign/php/ COPY foreign/php/README.md foreign/php/LICENSE foreign/php/NOTICE ./foreign/php/ COPY foreign/php/.cargo/ ./foreign/php/.cargo/ COPY foreign/php/src/ ./foreign/php/src/ @@ -51,7 +55,8 @@ COPY foreign/php/scripts/ ./foreign/php/scripts/ WORKDIR /workspace/foreign/php RUN cargo install cargo-php --locked -RUN cargo php install --release --yes +RUN composer install --no-interaction --prefer-dist +RUN cargo php install --yes RUN chmod +x ./scripts/test.sh CMD ["./scripts/test.sh"] diff --git a/foreign/php/README.md b/foreign/php/README.md index e9de15c932..dd834ad328 100644 --- a/foreign/php/README.md +++ b/foreign/php/README.md @@ -11,6 +11,7 @@ synchronous PHP API over the Rust Iggy client. - Rust and Cargo - PHP with `php-config` - `cargo-php` +- Composer, for installing PHPUnit - Docker, for running the integration test server On macOS with Homebrew PHP: @@ -109,7 +110,8 @@ docker compose -f docker-compose.test.yml up --build --abort-on-container-exit - Run the PHP test suite: ```sh -php tests/run.php +composer install +composer test ``` Run Rust verification: diff --git a/foreign/php/composer.json b/foreign/php/composer.json index 4b7b1a7bb7..4b5c64debd 100644 --- a/foreign/php/composer.json +++ b/foreign/php/composer.json @@ -3,7 +3,10 @@ "description": "PHP extension bindings for Apache Iggy.", "license": "Apache-2.0", "type": "library", + "require-dev": { + "phpunit/phpunit": "^10.5" + }, "scripts": { - "test": "php tests/run.php" + "test": "phpunit" } } diff --git a/foreign/php/phpunit.xml.dist b/foreign/php/phpunit.xml.dist new file mode 100644 index 0000000000..7403e076cd --- /dev/null +++ b/foreign/php/phpunit.xml.dist @@ -0,0 +1,11 @@ + + + + + tests + + + diff --git a/foreign/php/scripts/test.sh b/foreign/php/scripts/test.sh index dfa5c5afde..6c964ace24 100755 --- a/foreign/php/scripts/test.sh +++ b/foreign/php/scripts/test.sh @@ -41,4 +41,4 @@ if [ -n "${PHP_IGGY_EXTENSION:-}" ]; then PHP_ARGS+=("-d" "extension=${PHP_IGGY_EXTENSION}") fi -"${PHP_BIN}" "${PHP_ARGS[@]}" tests/run.php "$@" +"${PHP_BIN}" "${PHP_ARGS[@]}" vendor/bin/phpunit "$@" diff --git a/foreign/php/src/client.rs b/foreign/php/src/client.rs index 0945532b21..a1efcd0911 100644 --- a/foreign/php/src/client.rs +++ b/foreign/php/src/client.rs @@ -23,7 +23,7 @@ use ext_php_rs::{ php_class, php_impl, }; use iggy::prelude::{ - CompressionAlgorithm, Consumer as RustConsumer, Identifier, IggyClient as RustIggyClient, + CompressionAlgorithm, Consumer as RustConsumer, IggyClient as RustIggyClient, IggyClientBuilder, IggyDuration, IggyExpiry, IggyMessage as RustMessage, MaxTopicSize, Partitioning, PollingStrategy as RustPollingStrategy, *, }; @@ -32,6 +32,7 @@ use tokio::sync::Mutex; use crate::consumer::{AutoCommit, IggyConsumer}; use crate::identifier::PhpIdentifier; use crate::receive_message::{PollingStrategy, ReceiveMessage}; +use crate::runtime::runtime; use crate::send_message::SendMessage; use crate::stream::StreamDetails; use crate::topic::TopicDetails; @@ -108,7 +109,7 @@ impl IggyClient { /// Gets a stream by id or name. pub fn get_stream(&self, stream_id: PhpIdentifier) -> PhpResult> { - let stream_id = Identifier::from(stream_id); + let stream_id = stream_id.into_identifier()?; let inner = self.inner.clone(); runtime().block_on(async move { @@ -142,7 +143,7 @@ impl IggyClient { IggyExpiry::ExpireDuration(iggy_duration_from_micros(micros)) }); let max_size = max_topic_size.map_or(MaxTopicSize::ServerDefault, MaxTopicSize::from); - let stream = Identifier::from(stream); + let stream = stream.into_identifier()?; let inner = self.inner.clone(); runtime().block_on(async move { @@ -168,8 +169,8 @@ impl IggyClient { stream_id: PhpIdentifier, topic_id: PhpIdentifier, ) -> PhpResult> { - let stream_id = Identifier::from(stream_id); - let topic_id = Identifier::from(topic_id); + let stream_id = stream_id.into_identifier()?; + let topic_id = topic_id.into_identifier()?; let inner = self.inner.clone(); runtime().block_on(async move { @@ -189,8 +190,8 @@ impl IggyClient { partition_id: u32, messages: Vec<&SendMessage>, ) -> PhpResult { - let stream = Identifier::from(stream); - let topic = Identifier::from(topic); + let stream = stream.into_identifier()?; + let topic = topic.into_identifier()?; let partitioning = Partitioning::partition_id(partition_id); let mut messages: Vec = messages .into_iter() @@ -217,8 +218,8 @@ impl IggyClient { auto_commit: bool, ) -> PhpResult> { let consumer = RustConsumer::default(); - let stream = Identifier::from(stream); - let topic = Identifier::from(topic); + let stream = stream.into_identifier()?; + let topic = topic.into_identifier()?; let strategy: RustPollingStrategy = polling_strategy.into(); let inner = self.inner.clone(); @@ -337,14 +338,3 @@ fn to_php_exception(error: impl std::fmt::Display) -> PhpException { fn iggy_duration_from_micros(micros: u64) -> IggyDuration { IggyDuration::new(Duration::from_micros(micros)) } - -fn runtime() -> &'static tokio::runtime::Runtime { - static RUNTIME: std::sync::OnceLock = std::sync::OnceLock::new(); - - RUNTIME.get_or_init(|| { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("failed to initialize Tokio runtime") - }) -} diff --git a/foreign/php/src/consumer.rs b/foreign/php/src/consumer.rs index 12cdc89248..65fa83215f 100644 --- a/foreign/php/src/consumer.rs +++ b/foreign/php/src/consumer.rs @@ -23,13 +23,15 @@ use ext_php_rs::{ php_class, php_impl, types::ZendCallable, }; +use futures::StreamExt; use iggy::prelude::{ AutoCommit as RustAutoCommit, AutoCommitAfter as RustAutoCommitAfter, AutoCommitWhen as RustAutoCommitWhen, IggyConsumer as RustIggyConsumer, IggyDuration, }; use tokio::sync::Mutex; -use crate::iterator::ReceiveMessageIterator; +use crate::receive_message::ReceiveMessage; +use crate::runtime::runtime; /// A PHP class representing the Iggy consumer. #[php_class] @@ -41,36 +43,32 @@ pub struct IggyConsumer { impl IggyConsumer { /// Get the last consumed offset or null if no offset has been consumed yet. pub fn get_last_consumed_offset(&self, partition_id: u32) -> Option { - self.inner - .blocking_lock() - .get_last_consumed_offset(partition_id) + self.with_consumer(|inner| inner.get_last_consumed_offset(partition_id)) } /// Get the last stored offset or null if no offset has been stored yet. pub fn get_last_stored_offset(&self, partition_id: u32) -> Option { - self.inner - .blocking_lock() - .get_last_stored_offset(partition_id) + self.with_consumer(|inner| inner.get_last_stored_offset(partition_id)) } /// Gets the name of the consumer group. pub fn name(&self) -> String { - self.inner.blocking_lock().name().to_string() + self.with_consumer(|inner| inner.name().to_string()) } /// Gets the current partition id or 0 if no messages have been polled yet. pub fn partition_id(&self) -> u32 { - self.inner.blocking_lock().partition_id() + self.with_consumer(RustIggyConsumer::partition_id) } /// Gets the stream identifier this consumer is configured for. pub fn stream(&self) -> String { - self.inner.blocking_lock().stream().to_string() + self.with_consumer(|inner| inner.stream().to_string()) } /// Gets the topic identifier this consumer is configured for. pub fn topic(&self) -> String { - self.inner.blocking_lock().topic().to_string() + self.with_consumer(|inner| inner.topic().to_string()) } /// Stores the provided offset for the provided partition id. @@ -105,13 +103,6 @@ impl IggyConsumer { }) } - /// Returns an iterator whose next() method blocks until a message is available. - pub fn iter_messages(&self) -> ReceiveMessageIterator { - ReceiveMessageIterator { - inner: self.inner.clone(), - } - } - /// Consumes messages with a PHP callback. /// /// The callback is called as callback(ReceiveMessage $message). If limit is null, @@ -121,7 +112,7 @@ impl IggyConsumer { let max_messages = limit.unwrap_or(u32::MAX); while consumed < max_messages { - let Some(message) = self.iter_messages().next()? else { + let Some(message) = self.next_message()? else { break; }; @@ -135,6 +126,34 @@ impl IggyConsumer { } } +impl IggyConsumer { + fn with_consumer(&self, f: impl FnOnce(&RustIggyConsumer) -> T) -> T { + let inner = self.inner.clone(); + + runtime().block_on(async move { + let inner = inner.lock().await; + f(&inner) + }) + } + + fn next_message(&self) -> PhpResult> { + let inner = self.inner.clone(); + + runtime().block_on(async move { + let mut inner = inner.lock().await; + + match inner.next().await { + Some(Ok(message)) => Ok(Some(ReceiveMessage { + inner: message.message, + partition_id: message.partition_id, + })), + Some(Err(err)) => Err(PhpException::default(err.to_string())), + None => Ok(None), + } + }) + } +} + #[php_class] #[derive(Clone, Copy)] pub struct AutoCommit { @@ -267,14 +286,3 @@ impl From<&AutoCommitAfter> for RustAutoCommitAfter { fn iggy_duration_from_micros(micros: u64) -> IggyDuration { IggyDuration::new(Duration::from_micros(micros)) } - -fn runtime() -> &'static tokio::runtime::Runtime { - static RUNTIME: std::sync::OnceLock = std::sync::OnceLock::new(); - - RUNTIME.get_or_init(|| { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("failed to initialize Tokio runtime") - }) -} diff --git a/foreign/php/src/identifier.rs b/foreign/php/src/identifier.rs index 9087c2728a..ae751516e9 100644 --- a/foreign/php/src/identifier.rs +++ b/foreign/php/src/identifier.rs @@ -18,7 +18,12 @@ use std::str::FromStr; -use ext_php_rs::{convert::FromZval, flags::DataType, types::Zval}; +use ext_php_rs::{ + convert::FromZval, + exception::{PhpException, PhpResult}, + flags::DataType, + types::Zval, +}; use iggy::prelude::{IdKind, Identifier}; pub enum PhpIdentifier { @@ -40,20 +45,29 @@ impl FromZval<'_> for PhpIdentifier { } } -impl From for Identifier { - fn from(identifier: PhpIdentifier) -> Self { - match identifier { - PhpIdentifier::String(value) => Identifier::from_str(&value).unwrap(), - PhpIdentifier::Int(value) => Identifier::numeric(value).unwrap(), +impl PhpIdentifier { + pub(crate) fn into_identifier(self) -> PhpResult { + match self { + PhpIdentifier::String(value) => Identifier::from_str(&value), + PhpIdentifier::Int(value) => Identifier::numeric(value), } + .map_err(|err| PhpException::default(err.to_string())) } } -impl From<&Identifier> for PhpIdentifier { - fn from(value: &Identifier) -> PhpIdentifier { +impl TryFrom<&Identifier> for PhpIdentifier { + type Error = PhpException; + + fn try_from(value: &Identifier) -> Result { match value.kind { - IdKind::String => PhpIdentifier::String(value.get_string_value().unwrap()), - IdKind::Numeric => PhpIdentifier::Int(value.get_u32_value().unwrap()), + IdKind::String => value + .get_string_value() + .map(PhpIdentifier::String) + .map_err(|err| PhpException::default(err.to_string())), + IdKind::Numeric => value + .get_u32_value() + .map(PhpIdentifier::Int) + .map_err(|err| PhpException::default(err.to_string())), } } } diff --git a/foreign/php/src/iterator.rs b/foreign/php/src/iterator.rs deleted file mode 100644 index fa599bdedf..0000000000 --- a/foreign/php/src/iterator.rs +++ /dev/null @@ -1,65 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -use std::{sync::Arc, sync::OnceLock}; - -use ext_php_rs::{ - exception::{PhpException, PhpResult}, - php_class, php_impl, -}; -use futures::StreamExt; -use iggy::prelude::IggyConsumer as RustIggyConsumer; -use tokio::{runtime::Runtime, sync::Mutex}; - -use crate::receive_message::ReceiveMessage; - -#[php_class] -pub struct ReceiveMessageIterator { - pub(crate) inner: Arc>, -} - -#[php_impl] -impl ReceiveMessageIterator { - pub fn next(&self) -> PhpResult> { - let inner = self.inner.clone(); - - runtime().block_on(async move { - let mut inner = inner.lock().await; - - match inner.next().await { - Some(Ok(message)) => Ok(Some(ReceiveMessage { - inner: message.message, - partition_id: message.partition_id, - })), - Some(Err(err)) => Err(PhpException::default(err.to_string())), - None => Ok(None), - } - }) - } -} - -pub fn runtime() -> &'static Runtime { - static RUNTIME: OnceLock = OnceLock::new(); - - RUNTIME.get_or_init(|| { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("failed to initialize Tokio runtime") - }) -} diff --git a/foreign/php/src/lib.rs b/foreign/php/src/lib.rs index 79051abd70..40975e57c0 100644 --- a/foreign/php/src/lib.rs +++ b/foreign/php/src/lib.rs @@ -19,8 +19,8 @@ pub mod client; pub mod consumer; pub mod identifier; -pub mod iterator; pub mod receive_message; +pub mod runtime; pub mod send_message; pub mod stream; pub mod topic; @@ -29,7 +29,6 @@ use ext_php_rs::prelude::*; use crate::client::IggyClient; use crate::consumer::{AutoCommit, AutoCommitAfter, AutoCommitWhen, IggyConsumer}; -use crate::iterator::ReceiveMessageIterator; use crate::receive_message::{PollingStrategy, ReceiveMessage}; use crate::send_message::SendMessage; use crate::stream::StreamDetails; @@ -43,7 +42,6 @@ pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { .class::() .class::() .class::() - .class::() .class::() .class::() .class::() diff --git a/foreign/php/src/receive_message.rs b/foreign/php/src/receive_message.rs index 71c071ca18..e34501a84e 100644 --- a/foreign/php/src/receive_message.rs +++ b/foreign/php/src/receive_message.rs @@ -21,9 +21,9 @@ use iggy::prelude::{ IggyMessage as RustReceiveMessage, IggyMessageHeader, PollingStrategy as RustPollingStrategy, }; -/// A Python class representing a received message. +/// A PHP class representing a received message. /// -/// This class wraps a Rust message, allowing for access to its payload and offset from Python. +/// This class wraps a Rust message, allowing PHP code to access its payload and metadata. #[php_class] pub struct ReceiveMessage { pub(crate) inner: RustReceiveMessage, diff --git a/foreign/php/src/runtime.rs b/foreign/php/src/runtime.rs new file mode 100644 index 0000000000..c223db0ba2 --- /dev/null +++ b/foreign/php/src/runtime.rs @@ -0,0 +1,30 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +use std::sync::OnceLock; + +pub fn runtime() -> &'static tokio::runtime::Runtime { + static RUNTIME: OnceLock = OnceLock::new(); + + RUNTIME.get_or_init(|| { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .expect("failed to initialize Tokio runtime") + }) +} diff --git a/foreign/php/src/send_message.rs b/foreign/php/src/send_message.rs index 07638d5480..1d95bc6a56 100644 --- a/foreign/php/src/send_message.rs +++ b/foreign/php/src/send_message.rs @@ -58,7 +58,13 @@ impl SendMessage { /// PHP strings are byte strings, so this accepts both text and binary payloads. #[php(constructor)] pub fn __construct(data: Binary) -> PhpResult { - Self::from_payload(Vec::from(data)) + // `Binary` already owns the PHP string bytes; `Bytes::from(Vec<_>)` reuses that buffer. + let inner = RustIggyMessage::builder() + .payload(Bytes::from(Vec::::from(data))) + .build() + .map_err(|err| PhpException::default(err.to_string()))?; + + Ok(Self { inner }) } #[php(getter)] @@ -71,14 +77,3 @@ impl SendMessage { Binary::new(self.inner.payload.to_vec()) } } - -impl SendMessage { - fn from_payload(payload: Vec) -> PhpResult { - let inner = RustIggyMessage::builder() - .payload(Bytes::from(payload)) - .build() - .map_err(|err| PhpException::default(err.to_string()))?; - - Ok(Self { inner }) - } -} diff --git a/foreign/php/tests/IggySdkTest.php b/foreign/php/tests/IggySdkTest.php index dfa3d57c34..bf39d35b69 100644 --- a/foreign/php/tests/IggySdkTest.php +++ b/foreign/php/tests/IggySdkTest.php @@ -21,7 +21,9 @@ declare(strict_types=1); -final class IggySdkTest +use PHPUnit\Framework\TestCase; + +final class IggySdkTest extends TestCase { public function testPing(): void { @@ -97,38 +99,14 @@ public function testListTopicsViaGetTopic(): void assert_same(1, $topic->partitions_count); } - public function testSendAndPollMessages(): void + public function testSendAndPollBinaryMessages(): void { $client = new_client(); $streamName = unique_name('msg-stream'); $topicName = unique_name('msg-topic'); $partitionId = 0; $messages = array_map( - static fn (int $i): string => "Test message {$i} - {$streamName}", - range(1, 3), - ); - - create_stream_and_topic($client, $streamName, $topicName); - $client->sendMessages( - $streamName, - $topicName, - $partitionId, - array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), - ); - - $polled = $client->pollMessages($streamName, $topicName, $partitionId, PollingStrategy::first(), 10, true); - assert_true(count($polled) >= count($messages), 'expected at least the sent messages'); - assert_same($messages, array_slice(collect_payloads($polled), 0, count($messages))); - } - - public function testSendAndPollMessagesAsBytes(): void - { - $client = new_client(); - $streamName = unique_name('msg-stream'); - $topicName = unique_name('msg-topic'); - $partitionId = 0; - $messages = array_map( - static fn (int $i): string => "Binary message {$i} - {$streamName}", + static fn (int $i): string => random_bytes(16) . pack('C*', 0, $i, 255), range(1, 3), ); @@ -314,51 +292,4 @@ static function (ReceiveMessage $message) use (&$received): void { assert_same($messages, $received); } - public function testIterMessages(): void - { - $client = new_client(); - $consumerName = unique_name('consumer-group-consumer'); - $streamName = unique_name('consumer-group-stream'); - $topicName = unique_name('consumer-group-topic'); - $partitionId = 0; - $messages = array_map( - static fn (int $i): string => "Iterator test {$i} - {$streamName}", - range(0, 4), - ); - - create_stream_and_topic($client, $streamName, $topicName); - $client->sendMessages( - $streamName, - $topicName, - $partitionId, - array_map(static fn (string $payload): SendMessage => new SendMessage($payload), $messages), - ); - - $consumer = $client->consumerGroup( - $consumerName, - $streamName, - $topicName, - $partitionId, - PollingStrategy::next(), - 10, - AutoCommit::interval(micros(5)), - true, - true, - micros(1), - null, - null, - null, - false, - ); - - $iterator = $consumer->iterMessages(); - $received = []; - while (count($received) < count($messages)) { - $message = $iterator->next(); - assert_not_null($message); - $received[] = $message->payload(); - } - - assert_same($messages, $received); - } } diff --git a/foreign/php/tests/TlsTest.php b/foreign/php/tests/TlsTest.php index 4798bdee2b..c3404d1c0f 100644 --- a/foreign/php/tests/TlsTest.php +++ b/foreign/php/tests/TlsTest.php @@ -21,13 +21,15 @@ declare(strict_types=1); -final class TlsTest +use PHPUnit\Framework\TestCase; + +final class TlsTest extends TestCase { public function testConnectionStringWithTlsParams(): void { $connectionString = getenv('IGGY_TLS_CONNECTION_STRING'); if ($connectionString === false || $connectionString === '') { - throw new SkippedTest('set IGGY_TLS_CONNECTION_STRING to run TLS tests'); + $this->markTestSkipped('set IGGY_TLS_CONNECTION_STRING to run TLS tests'); } $client = IggyClient::fromConnectionString($connectionString); @@ -39,7 +41,7 @@ public function testProduceAndConsumeOverTls(): void { $connectionString = getenv('IGGY_TLS_CONNECTION_STRING'); if ($connectionString === false || $connectionString === '') { - throw new SkippedTest('set IGGY_TLS_CONNECTION_STRING to run TLS tests'); + $this->markTestSkipped('set IGGY_TLS_CONNECTION_STRING to run TLS tests'); } $client = IggyClient::fromConnectionString($connectionString); @@ -68,15 +70,10 @@ public function testConnectWithoutTlsShouldFail(): void { $address = getenv('IGGY_TLS_PLAINTEXT_ADDRESS'); if ($address === false || $address === '') { - throw new SkippedTest('set IGGY_TLS_PLAINTEXT_ADDRESS to run this TLS failure test'); + $this->markTestSkipped('set IGGY_TLS_PLAINTEXT_ADDRESS to run this TLS failure test'); } $client = new IggyClient($address); assert_throws(static fn () => $client->connect()); } } - -final class SkippedTest extends RuntimeException -{ -} - diff --git a/foreign/php/tests/bootstrap.php b/foreign/php/tests/bootstrap.php index d64c575f63..e0f914a55e 100644 --- a/foreign/php/tests/bootstrap.php +++ b/foreign/php/tests/bootstrap.php @@ -21,37 +21,26 @@ declare(strict_types=1); -final class TestFailure extends RuntimeException -{ -} +use PHPUnit\Framework\Assert; function assert_true(bool $condition, string $message = 'expected condition to be true'): void { - if (!$condition) { - throw new TestFailure($message); - } + Assert::assertTrue($condition, $message); } function assert_same(mixed $expected, mixed $actual, string $message = ''): void { - if ($expected !== $actual) { - $message = $message !== '' ? $message . ': ' : ''; - throw new TestFailure($message . 'expected ' . var_export($expected, true) . ', got ' . var_export($actual, true)); - } + Assert::assertSame($expected, $actual, $message); } function assert_not_null(mixed $value, string $message = 'expected value not to be null'): void { - if ($value === null) { - throw new TestFailure($message); - } + Assert::assertNotNull($value, $message); } function assert_null(mixed $value, string $message = 'expected value to be null'): void { - if ($value !== null) { - throw new TestFailure($message . ', got ' . var_export($value, true)); - } + Assert::assertNull($value, $message); } function assert_throws(callable $callback, ?string $messageContains = null): Throwable @@ -60,7 +49,7 @@ function assert_throws(callable $callback, ?string $messageContains = null): Thr $callback(); } catch (Throwable $throwable) { if ($messageContains !== null && !str_contains($throwable->getMessage(), $messageContains)) { - throw new TestFailure( + Assert::fail( 'expected exception message to contain ' . var_export($messageContains, true) . ', got ' . var_export($throwable->getMessage(), true) ); @@ -69,7 +58,7 @@ function assert_throws(callable $callback, ?string $messageContains = null): Thr return $throwable; } - throw new TestFailure('expected callable to throw'); + Assert::fail('expected callable to throw'); } function unique_name(string $prefix): string @@ -111,7 +100,7 @@ function wait_for_server(string $host, int $port, int $timeoutSeconds = 30): voi usleep(250_000); } - throw new TestFailure("Iggy server was not reachable at {$host}:{$port}" . ($lastError !== null ? " ({$lastError})" : '')); + Assert::fail("Iggy server was not reachable at {$host}:{$port}" . ($lastError !== null ? " ({$lastError})" : '')); } function new_client(): IggyClient @@ -151,3 +140,9 @@ function micros(int $seconds): int { return $seconds * 1_000_000; } + +if (!extension_loaded('iggy-php')) { + Assert::fail('The iggy-php extension is not loaded.'); +} + +wait_for_server(server_host(), server_port()); diff --git a/foreign/php/tests/run.php b/foreign/php/tests/run.php deleted file mode 100644 index 77d1e9b1e3..0000000000 --- a/foreign/php/tests/run.php +++ /dev/null @@ -1,80 +0,0 @@ -getMethods(ReflectionMethod::IS_PUBLIC) as $method) { - if (!str_starts_with($method->getName(), 'test')) { - continue; - } - - $name = $class . '::' . $method->getName(); - if ($filter !== null && !str_contains($name, $filter)) { - continue; - } - - try { - $method->invoke($instance); - $passed++; - fwrite(STDOUT, "PASS {$name}\n"); - } catch (ReflectionException $exception) { - $failed++; - fwrite(STDERR, "FAIL {$name}: {$exception->getMessage()}\n"); - } catch (Throwable $throwable) { - $previous = $throwable instanceof ReflectionException ? $throwable->getPrevious() : null; - $error = $previous ?? $throwable; - - if ($error instanceof SkippedTest) { - $skipped++; - fwrite(STDOUT, "SKIP {$name}: {$error->getMessage()}\n"); - continue; - } - - $failed++; - fwrite(STDERR, "FAIL {$name}: {$error->getMessage()}\n"); - } - } -} - -fwrite(STDOUT, "\n{$passed} passed, {$skipped} skipped, {$failed} failed\n"); -exit($failed === 0 ? 0 : 1);