[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: 🐛 Bug Report\nabout: If something isn't working as expected 🤔.\n\n---\n\n## Bug Report\n<!--\nThank you for reporting an issue.\n\nPlease fill in as much of the template below as you're able.\n-->\n\n### Version\n\n<!--\nList the versions of all `tonic` crates you are using. The easiest way to get\nthis information is using `cargo-tree`.\n\n`cargo install cargo-tree`\n(see install here: https://github.com/sfackler/cargo-tree)\n\nThen:\n\n`cargo tree | grep tonic`\n-->\n\n### Platform\n\n<!---\nOutput of `uname -a` (UNIX), or version and 32 or 64-bit (Windows)\n-->\n\n### Crates\n\n<!--\nIf known, please specify the affected tonic crates. Otherwise, delete this\nsection.\n-->\n\n### Description\n\n<!--\n\nEnter your issue details below this comment.\n\nOne way to structure the description:\n\n<short summary of the bug>\n\nI tried this code:\n\n<code sample that causes the bug>\n\nI expected to see this happen: <explanation>\n\nInstead, this happened: <explanation>\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: 💡 Feature Request\nabout: I have a suggestion (and may want to implement it 🙂)!\n\n---\n\n## Feature Request\n\n### Crates\n\n<!--\nIf known, please specify the tonic crate or crates the new feature should\nbe added to. Otherwise, delete this section.\n-->\n\n### Motivation\n\n<!--\nPlease describe the use case(s) or other motivation for the new feature.\n-->\n\n### Proposal\n\n<!--\nHow should the new feature be implemented, and why? Add any considered\ndrawbacks.\n-->\n\n### Alternatives\n\n<!--\nAre there other ways to solve this problem that you've considered? What are\ntheir potential drawbacks? Why was the proposed solution chosen over these\nalternatives?\n-->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nThank you for your Pull Request. Please provide a description above and review\nthe requirements below.\n\nIf this change is intended for tonic `v0.14.x` please make this PR against that branch\notherwise, it may not get included in a relase for a long time.\n\nBug fixes and new features should include tests.\n\nContributors guide: https://github.com/hyperium/tonic/blob/master/CONTRIBUTING.md\n-->\n\n## Motivation\n\n<!--\nExplain the context and why you're making that change. What is the problem\nyou're trying to solve? If a new feature is being added, describe the intended\nuse case that feature fulfills.\n-->\n\n## Solution\n\n<!--\nSummarize the solution and provide any necessary context needed to understand\nthe code change.\n-->\n"
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: CI\n\non:\n  push:\n  pull_request: {}\n  merge_group:\n    branches: [ \"master\" ]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n\n  rustfmt:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        components: rustfmt\n    - run: cargo fmt --all --check\n\n  build-protoc-plugin:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macOS-latest, windows-latest]\n    outputs:\n      cache-hit: ${{ steps.cache-plugin.outputs.cache-hit }}\n    steps:\n      - uses: actions/checkout@v6\n      - name: Cache protoc and plugin\n        id: cache-plugin\n        uses: actions/cache@v4\n        with:\n          path: ${{ runner.temp }}/protoc-plugin\n          # The key changes only when plugin source files or CMake files change\n          key: ${{ runner.os }}-protoc-plugin-cmake-v4-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/CMakeLists.txt', 'protoc-gen-rust-grpc/cmake/**') }}\n      - name: Install CMake\n        if: steps.cache-plugin.outputs.cache-hit != 'true'\n        uses: lukka/get-cmake@latest\n        with:\n          cmakeVersion: \"~3.28.0\"\n      # Building the protoc plugin from scratch takes 6–14 minutes, depending on\n      # the OS. This delays the execution of workflows that use the plugin in\n      # build.rs files. We try to avoid rebuilding the plugin if it hasn't\n      # changed.\n      - name: Build protoc plugin\n        if: steps.cache-plugin.outputs.cache-hit != 'true'\n        working-directory: ./protoc-gen-rust-grpc\n        shell: bash\n        run: |\n          set -e\n          # Create build directory\n          mkdir -p build\n          cd build\n\n          # Configure with CMake\n          cmake .. -DCMAKE_BUILD_TYPE=Release -DPROTOBUF_VERSION=33.0\n\n          # Build with limited parallelism to avoid OOM\n          cmake --build . --parallel 2\n\n          # The target path needs to match the cache config.\n          TARGET_PATH=\"${{ runner.temp }}/protoc-plugin\"\n          mkdir -p \"${TARGET_PATH}\"\n\n          # Copy both protoc and the plugin\n          # First, find and copy protoc\n          PROTOC_FOUND=false\n          for protoc_path in \"bin/protoc\" \"bin/protoc.exe\" \"bin/Release/protoc.exe\" \"bin/Debug/protoc.exe\" \"_deps/protobuf-build/protoc\" \"_deps/protobuf-build/protoc.exe\" \"_deps/protobuf-build/Release/protoc.exe\" \"_deps/protobuf-build/Debug/protoc.exe\"; do\n            if [ -f \"$protoc_path\" ]; then\n              echo \"Found protoc at: $protoc_path\"\n              # Copy with explicit name to ensure it's called 'protoc' or 'protoc.exe'\n              if [[ \"$protoc_path\" == *.exe ]]; then\n                cp \"$protoc_path\" \"${TARGET_PATH}/protoc.exe\"\n                echo \"Copied to: ${TARGET_PATH}/protoc.exe\"\n              else\n                cp \"$protoc_path\" \"${TARGET_PATH}/protoc\"\n                chmod +x \"${TARGET_PATH}/protoc\"\n                echo \"Copied to: ${TARGET_PATH}/protoc\"\n              fi\n              PROTOC_FOUND=true\n              break\n            fi\n          done\n\n          if [ \"$PROTOC_FOUND\" = \"false\" ]; then\n            echo \"Error: protoc not found in expected locations\"\n            echo \"Searching for protoc in build directory:\"\n            find . -name \"protoc\" -o -name \"protoc.exe\" | head -20\n            exit 1\n          fi\n\n          # Copy protoc with its standard installation structure\n          echo \"Setting up protoc installation...\"\n\n          # protoc expects to find includes relative to its binary location\n          # Standard structure: bin/protoc and include/google/protobuf/*.proto\n\n          # First check if CMake created an install directory\n          if [ -d \"install\" ] && [ -f \"install/bin/protoc\" -o -f \"install/bin/protoc.exe\" ]; then\n            echo \"Found CMake install directory\"\n            cp -r install/* \"${TARGET_PATH}/\"\n          else\n            # Manual setup if no install directory\n            echo \"Creating manual protoc installation structure...\"\n\n            # The protoc binary should already be copied to TARGET_PATH\n            # Now find and copy the include files to the correct relative location\n            mkdir -p \"${TARGET_PATH}/include\"\n\n            # Find the protobuf include files\n            INCLUDE_FOUND=false\n            for include_path in \"_deps/protobuf-src/src\" \"_deps/protobuf-build/include\" \"include\"; do\n              if [ -d \"$include_path/google/protobuf\" ] && [ -f \"$include_path/google/protobuf/descriptor.proto\" ]; then\n                echo \"Found protobuf includes at: $include_path\"\n                cp -r \"$include_path/google\" \"${TARGET_PATH}/include/\"\n                INCLUDE_FOUND=true\n                break\n              fi\n            done\n\n            if [ \"$INCLUDE_FOUND\" = \"false\" ]; then\n              echo \"Warning: Could not find protobuf include files\"\n              echo \"Searching for descriptor.proto:\"\n              find . -name \"descriptor.proto\" -type f | grep -v \"test\" | head -10\n            fi\n          fi\n\n          # Then copy the plugin (handle different output locations)\n          if [ -f \"bin/protoc-gen-rust-grpc\" ]; then\n            cp bin/protoc-gen-rust-grpc \"${TARGET_PATH}/\"\n          elif [ -f \"bin/protoc-gen-rust-grpc.exe\" ]; then\n            cp bin/protoc-gen-rust-grpc.exe \"${TARGET_PATH}/\"\n          elif [ -f \"bin/Release/protoc-gen-rust-grpc.exe\" ]; then\n            # Windows Release build\n            cp bin/Release/protoc-gen-rust-grpc.exe \"${TARGET_PATH}/\"\n          elif [ -f \"bin/Debug/protoc-gen-rust-grpc.exe\" ]; then\n            # Windows Debug build (shouldn't happen with Release config, but just in case)\n            cp bin/Debug/protoc-gen-rust-grpc.exe \"${TARGET_PATH}/\"\n          else\n            echo \"Error: protoc-gen-rust-grpc not found\"\n            echo \"Looking for binary in common locations...\"\n            find . -name \"protoc-gen-rust-grpc*\" -type f 2>/dev/null | head -10\n            exit 1\n          fi\n\n  clippy:\n    runs-on: ubuntu-latest\n    needs: build-protoc-plugin\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        components: clippy\n    - name: Restore protoc and plugin from cache\n      id: cache-plugin\n      uses: actions/cache@v4\n      with:\n        path: ${{ runner.temp }}/protoc-plugin\n        key: ${{ runner.os }}-protoc-plugin-cmake-v4-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/CMakeLists.txt', 'protoc-gen-rust-grpc/cmake/**') }}\n    - name: Add protoc and plugin to PATH\n      shell: bash\n      run: |\n        # Use forward slashes for all paths in bash, even on Windows\n        PROTOC_DIR=\"${{ runner.temp }}/protoc-plugin\"\n        PROTOC_DIR=\"${PROTOC_DIR//\\\\/\\/}\"  # Convert backslashes to forward slashes\n\n        echo \"${PROTOC_DIR}\" >> $GITHUB_PATH\n\n        # Also set PROTOC for build scripts\n        if [ \"${{ runner.os }}\" = \"Windows\" ]; then\n          echo \"PROTOC=${PROTOC_DIR}/protoc.exe\" >> $GITHUB_ENV\n        else\n          echo \"PROTOC=${PROTOC_DIR}/protoc\" >> $GITHUB_ENV\n        fi\n\n        # Set the protoc include path only if it exists\n        if [ -d \"${PROTOC_DIR}/include\" ]; then\n          echo \"PROTOC_INCLUDE=${PROTOC_DIR}/include\" >> $GITHUB_ENV\n        fi\n    - uses: Swatinem/rust-cache@v2\n    - run: cargo clippy --workspace --all-features --all-targets\n\n  codegen:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n    - uses: Swatinem/rust-cache@v2\n    - run: cargo run --package codegen\n    - run: git diff --exit-code\n\n  udeps:\n    runs-on: ubuntu-latest\n    needs: build-protoc-plugin\n    steps:\n    - uses: actions/checkout@v6\n    - uses: dtolnay/rust-toolchain@master\n      with:\n        toolchain: nightly-2026-02-22\n    - uses: taiki-e/install-action@cargo-hack\n    - uses: taiki-e/install-action@cargo-udeps\n    - name: Restore protoc and plugin from cache\n      id: cache-plugin\n      uses: actions/cache@v4\n      with:\n        path: ${{ runner.temp }}/protoc-plugin\n        key: ${{ runner.os }}-protoc-plugin-cmake-v4-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/CMakeLists.txt', 'protoc-gen-rust-grpc/cmake/**') }}\n    - name: Add protoc and plugin to PATH\n      shell: bash\n      run: |\n        # Use forward slashes for all paths in bash, even on Windows\n        PROTOC_DIR=\"${{ runner.temp }}/protoc-plugin\"\n        PROTOC_DIR=\"${PROTOC_DIR//\\\\/\\/}\"  # Convert backslashes to forward slashes\n\n        echo \"${PROTOC_DIR}\" >> $GITHUB_PATH\n\n        # Also set PROTOC for build scripts\n        if [ \"${{ runner.os }}\" = \"Windows\" ]; then\n          echo \"PROTOC=${PROTOC_DIR}/protoc.exe\" >> $GITHUB_ENV\n        else\n          echo \"PROTOC=${PROTOC_DIR}/protoc\" >> $GITHUB_ENV\n        fi\n\n        # Set the protoc include path only if it exists\n        if [ -d \"${PROTOC_DIR}/include\" ]; then\n          echo \"PROTOC_INCLUDE=${PROTOC_DIR}/include\" >> $GITHUB_ENV\n        fi\n    - uses: Swatinem/rust-cache@v2\n    - run: cargo hack udeps --workspace --exclude-features=_tls-any,tls,tls-aws-lc,tls-ring,tls-connect-info --each-feature\n    - run: cargo udeps --package tonic --features tls-ring,transport\n    - run: cargo udeps --package tonic --features tls-ring,server\n    - run: cargo udeps --package tonic --features tls-ring,channel\n    - run: cargo udeps --package tonic --features tls-aws-lc,transport\n    - run: cargo udeps --package tonic --features tls-aws-lc,server\n    - run: cargo udeps --package tonic --features tls-aws-lc,channel\n    - run: cargo udeps --package tonic --features tls-connect-info\n\n  check:\n    runs-on: ${{ matrix.os }}\n    needs: build-protoc-plugin\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macOS-latest, windows-latest]\n    env:\n      RUSTFLAGS: \"-D warnings\"\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n    - uses: taiki-e/install-action@cargo-hack\n    - name: Restore protoc and plugin from cache\n      id: cache-plugin\n      uses: actions/cache@v4\n      with:\n        path: ${{ runner.temp }}/protoc-plugin\n        key: ${{ runner.os }}-protoc-plugin-cmake-v4-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/CMakeLists.txt', 'protoc-gen-rust-grpc/cmake/**') }}\n    - name: Add protoc and plugin to PATH\n      shell: bash\n      run: |\n        # Use forward slashes for all paths in bash, even on Windows\n        PROTOC_DIR=\"${{ runner.temp }}/protoc-plugin\"\n        PROTOC_DIR=\"${PROTOC_DIR//\\\\/\\/}\"  # Convert backslashes to forward slashes\n\n        echo \"${PROTOC_DIR}\" >> $GITHUB_PATH\n\n        # Also set PROTOC for build scripts\n        if [ \"${{ runner.os }}\" = \"Windows\" ]; then\n          echo \"PROTOC=${PROTOC_DIR}/protoc.exe\" >> $GITHUB_ENV\n        else\n          echo \"PROTOC=${PROTOC_DIR}/protoc\" >> $GITHUB_ENV\n        fi\n\n        # Set the protoc include path only if it exists\n        if [ -d \"${PROTOC_DIR}/include\" ]; then\n          echo \"PROTOC_INCLUDE=${PROTOC_DIR}/include\" >> $GITHUB_ENV\n        fi\n    - uses: Swatinem/rust-cache@v2\n    - name: Check features\n      run: cargo hack check --workspace --no-private --each-feature --no-dev-deps\n    - name: Check tonic feature powerset\n      run: cargo hack check --package tonic --feature-powerset --depth 2\n    - name: Check all targets\n      run: cargo check --workspace --all-targets --all-features\n\n  msrv:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n    - name: Resolve MSRV aware dependencies\n      run: cargo update\n      env:\n        CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback\n    - name: Get MSRV from manifest file\n      id: msrv\n      run: echo \"version=$(yq '.workspace.package.rust-version' Cargo.toml)\" >> \"$GITHUB_OUTPUT\"\n    - uses: hecrj/setup-rust-action@v2\n      with:\n        rust-version: ${{ steps.msrv.outputs.version }}\n    - uses: taiki-e/install-action@cargo-no-dev-deps\n    - uses: Swatinem/rust-cache@v2\n    # we exlude crates that do not use rust-version = { workspace = true }\n    - run: cargo no-dev-deps --no-private check --all-features --workspace --exclude grpc --exclude tonic-protobuf\\*\n\n  doc:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - uses: dtolnay/rust-toolchain@nightly\n    - uses: dtolnay/install@cargo-docs-rs\n    - uses: taiki-e/install-action@cargo-hack\n    - uses: Swatinem/rust-cache@v2\n    - run: cargo +nightly hack --no-private docs-rs\n      env:\n        RUSTDOCFLAGS: \"-D warnings\"\n\n  test:\n    runs-on: ${{ matrix.os }}\n    needs: build-protoc-plugin\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macOS-latest, windows-latest]\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n    - name: Restore protoc and plugin from cache\n      id: cache-plugin\n      uses: actions/cache@v4\n      with:\n        path: ${{ runner.temp }}/protoc-plugin\n        key: ${{ runner.os }}-protoc-plugin-cmake-v4-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/CMakeLists.txt', 'protoc-gen-rust-grpc/cmake/**') }}\n    - name: Check cache status\n      if: steps.cache-plugin.outputs.cache-hit != 'true'\n      run: |\n        echo \"ERROR: Cache miss! The protoc plugin was not found in cache.\"\n        echo \"This means the build-protoc-plugin job either failed or didn't run.\"\n        exit 1\n    - name: Add protoc and plugin to PATH\n      shell: bash\n      run: |\n        # Use forward slashes for all paths in bash, even on Windows\n        PROTOC_DIR=\"${{ runner.temp }}/protoc-plugin\"\n        PROTOC_DIR=\"${PROTOC_DIR//\\\\/\\/}\"  # Convert backslashes to forward slashes\n\n        echo \"${PROTOC_DIR}\" >> $GITHUB_PATH\n\n        # Also set PROTOC for build scripts\n        if [ \"${{ runner.os }}\" = \"Windows\" ]; then\n          echo \"PROTOC=${PROTOC_DIR}/protoc.exe\" >> $GITHUB_ENV\n        else\n          echo \"PROTOC=${PROTOC_DIR}/protoc\" >> $GITHUB_ENV\n        fi\n\n        # Set the protoc include path only if it exists\n        if [ -d \"${PROTOC_DIR}/include\" ]; then\n          echo \"PROTOC_INCLUDE=${PROTOC_DIR}/include\" >> $GITHUB_ENV\n        fi\n    - uses: taiki-e/install-action@cargo-hack\n    - uses: taiki-e/install-action@cargo-nextest\n    - uses: Swatinem/rust-cache@v2\n    - run: cargo nextest run --workspace --all-features\n      env:\n        QUICKCHECK_TESTS: 1000  # run a lot of quickcheck iterations\n\n  doc-test:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n    - uses: taiki-e/install-action@cargo-hack\n    - uses: Swatinem/rust-cache@v2\n    - run: cargo hack --no-private test --doc --all-features\n\n  interop:\n    name: Interop Tests\n    runs-on: ${{ matrix.os }}\n    needs: build-protoc-plugin\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macOS-latest, windows-latest]\n    steps:\n    - uses: actions/checkout@v6\n    - uses: hecrj/setup-rust-action@v2\n    - name: Restore protoc and plugin from cache\n      id: cache-plugin\n      uses: actions/cache@v4\n      with:\n        path: ${{ runner.temp }}/protoc-plugin\n        key: ${{ runner.os }}-protoc-plugin-cmake-v4-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/CMakeLists.txt', 'protoc-gen-rust-grpc/cmake/**') }}\n    - name: Add protoc and plugin to PATH\n      shell: bash\n      run: |\n        # Use forward slashes for all paths in bash, even on Windows\n        PROTOC_DIR=\"${{ runner.temp }}/protoc-plugin\"\n        PROTOC_DIR=\"${PROTOC_DIR//\\\\/\\/}\"  # Convert backslashes to forward slashes\n\n        echo \"${PROTOC_DIR}\" >> $GITHUB_PATH\n\n        # Also set PROTOC for build scripts\n        if [ \"${{ runner.os }}\" = \"Windows\" ]; then\n          echo \"PROTOC=${PROTOC_DIR}/protoc.exe\" >> $GITHUB_ENV\n        else\n          echo \"PROTOC=${PROTOC_DIR}/protoc\" >> $GITHUB_ENV\n        fi\n\n        # Set the protoc include path only if it exists\n        if [ -d \"${PROTOC_DIR}/include\" ]; then\n          echo \"PROTOC_INCLUDE=${PROTOC_DIR}/include\" >> $GITHUB_ENV\n        fi\n    - uses: Swatinem/rust-cache@v2\n    - name: Run interop tests\n      run: ./interop/test.sh\n      shell: bash\n    - name: Run interop tests with Rustls\n      run: ./interop/test.sh --use_tls tls_rustls\n      shell: bash\n\n  semver:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - uses: obi1kenobi/cargo-semver-checks-action@v2\n      with:\n        feature-group: all-features\n\n  external-types:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n    - uses: dtolnay/rust-toolchain@master\n      with:\n        toolchain: nightly-2025-10-18\n    - name: Install cargo-check-external-types\n      uses: taiki-e/cache-cargo-install-action@v2\n      with:\n        tool: cargo-check-external-types@0.4.0\n    - uses: taiki-e/install-action@cargo-hack\n    - uses: Swatinem/rust-cache@v2\n    - run: cargo hack --no-private check-external-types --all-features\n      env:\n        RUSTFLAGS: \"-D warnings\"\n"
  },
  {
    "path": ".gitignore",
    "content": "target/\n**/*.rs.bk\nCargo.lock\ntags\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# NOTE: ths changelog is no longer used and from version `v0.13.0` onward we will be using github releases and the changes can be found [here](https://github.com/hyperium/tonic/releases).\n\n# [0.12.3](https://github.com/hyperium/tonic/compare/v0.12.2...v0.12.3) (2024-08-29)\n\n### Features\n\n* **server:** Added support for grpc max_connection_age (#1865)\n* **build:** Add `#[deprecated]` to deprecated client methods (#1879)\n* **build:** plumb skip_debug through prost Builder and add test (#1900)\n\n### Bug Fixes\n\n* **build:** Revert \"fix tonic-build cargo build script outputs (#1821)\" which accidentally increases MSRV (#1898)\n* **server:** ignore more error kinds in incoming socket stream (#1885)\n* **transport**: do not shutdown server on broken connections (#1948)\n\n# [0.12.2](https://github.com/hyperium/tonic/compare/v0.12.1...v0.12.2) (2024-08-23)\n\n### Features\n\n* Move TimeoutExpired out of transport (#1826)\n* Move ConnectError type from transport (#1828)\n* **channel:** allow setting max_header_list_size (#1835)\n* **router:** Add RoutesBuilder constructor (#1855)\n* **tls:** Rename tls-roots feature with tls-native-roots (#1860)\n* **router:** Rename Routes::into_router with into_axum_router (#1862)\n* **router:** Implement from axum::Router for Routes (#1863)\n* **channel:** Re-enable TLS based on Cargo features in generated clients (#1866)\n* **server:** allow setting max_header_list_size (#1870)\n* **build:** Expose formatted service name (#1684)\n* **reflection:** add back support for v1alpha reflection protocol (#1888)\n\n### Bug Fixes\n\n* **router:** Add missing unimplemented fallback to RoutesBuilder (#1864)\n* **server:** Prevent server from exiting on ECONNABORTED (#1874)\n* **web:** fix panic in trailer parsing on multiple trailers (#1880)\n* **web:** fix empty trailer parsing causing infinite parser loop (#1883)\n\n# [0.12.1](https://github.com/hyperium/tonic/compare/v0.12.0...v0.12.1) (2024-07-17)\n\n### Bug Fixes\n\n* Reduce tokio-stream feature (#1795)\n\n# [0.12.0](https://github.com/hyperium/tonic/compare/v0.11.0...v0.12.0) (2024-07-08)\n\nThis breaking release updates tonic to the hyper `1.0` ecosystem and also updates\nto prost `v0.13.0`.\n\n### Features\n\n* **build:** Custom codecs for generated code ([#1599](https://github.com/hyperium/tonic/issues/1599)) ([18a2b30](https://github.com/hyperium/tonic/commit/18a2b30922460be02829706cf9dd0cd1ec6a19c1))\n* **channel:** Make channel feature additive ([#1574](https://github.com/hyperium/tonic/issues/1574)) ([b947e1a](https://github.com/hyperium/tonic/commit/b947e1ac0727ceb0a0267a30854ada4ba18931db))\n* **codec:** Make error when not utf8 value in compression encoding ([#1768](https://github.com/hyperium/tonic/issues/1768)) ([f8e1f87](https://github.com/hyperium/tonic/commit/f8e1f87eb862676147fd6215b58c9090d259104d))\n* Implement http_body::Body::size_hint for custom body ([#1713](https://github.com/hyperium/tonic/issues/1713)) ([9728c01](https://github.com/hyperium/tonic/commit/9728c01132bd64dca046675198edc751c4547966))\n* Make boxed function public ([#1754](https://github.com/hyperium/tonic/issues/1754)) ([2cc868f](https://github.com/hyperium/tonic/commit/2cc868f80b20379d6635ac182f523b4971d016b7))\n* Relax GrpcMethod lifetime ([#1598](https://github.com/hyperium/tonic/issues/1598)) ([68bf17d](https://github.com/hyperium/tonic/commit/68bf17d67ad71af44c34d565566c3dd58ea3ab87))\n* **tls:** Add ability to add multiple ca certificates ([#1724](https://github.com/hyperium/tonic/issues/1724)) ([3457f92](https://github.com/hyperium/tonic/commit/3457f9203226f88524b31bf5d64ce6e5ec7c993c))\n* **tls:** Use rustls_pki_types::CertificateDer to describe DER encoded certificate ([#1707](https://github.com/hyperium/tonic/issues/1707)) ([96a8cbc](https://github.com/hyperium/tonic/commit/96a8cbc04d0cad6d30d2944dba6b32aac8975f91))\n* **tls:** Remove tls roots implicit configuration ([#1731](https://github.com/hyperium/tonic/issues/1731)) ([de73617](https://github.com/hyperium/tonic/commit/de736171f20ec5d485c26ee5eda4a9ccf5fc75e5))\n* **transport:** Make service router independent from transport ([#1572](https://github.com/hyperium/tonic/issues/1572)) ([da48235](https://github.com/hyperium/tonic/commit/da482359933f52e84c0263b28a5a83ab1efe6c33))\n* **transport:** Make transport server and channel independent ([#1630](https://github.com/hyperium/tonic/issues/1630)) ([654289f](https://github.com/hyperium/tonic/commit/654289fdc24f56d6845ec0ceb233deb46b640fac))\n* **transport:** Rename reexported axum body ([#1752](https://github.com/hyperium/tonic/issues/1752)) ([5d7bfc2](https://github.com/hyperium/tonic/commit/5d7bfc22c590982463f2d93464b0a7fb90e17083))\n* Use http::Extensions directly ([#1710](https://github.com/hyperium/tonic/issues/1710)) ([ed95d27](https://github.com/hyperium/tonic/commit/ed95d2762146f001970b74941f3bad77b7560426))\n\n### Bug Fixes\n\n* **tonic:** flush accumulated ready messages when status received ([#1756](https://github.com/hyperium/tonic/issues/1756)) ([d312dcc](https://github.com/hyperium/tonic/commit/d312dcc0ec362cb12f6e54072622761d7466a650)), closes [#1423](https://github.com/hyperium/tonic/issues/1423)\n\n### BREAKING CHANGES\n\n* `tonic` and crates updated to hyper 1.0 (#1670)\n* `tonic` and crates updated to prost 0.13 (#1779)\n* `tonic_reflection::server` is updated to use the generated\n  `tonic_reflection::pb::v1` code.\n* Make compression encoding configuration more malleable (#1757)\n* Removed implicit configuration of client TLS roots setup (#1731)\n\n\n[v1.8.8]: https://github.com/fullstorydev/grpcurl/releases/tag/v1.8.8\n[proto]: https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1/reflection.proto\n[grpcurl]: https://github.com/fullstorydev/grpcurl\n\n\n# [0.11.0](https://github.com/hyperium/tonic/compare/v0.10.2...v0.11.0) (2024-02-08)\n\nBREAKING CHANGES:\n\n- Removed `NamedService` from the `transport` module, please import it via\n    `tonic::server::NamedService`.\n- MSRV bumped to `1.70`.\n\n### Features\n\n- Added `zstd` compression support.\n- Added connection timeout for `connecto_with_connector_lazy`.\n- Upgrade rustls to `v0.22`\n- Feature gate server implementation for `tonic-reflection`.\n\n\n# [0.10.2](https://github.com/hyperium/tonic/compare/v0.10.1...v0.10.2) (2023-09-28)\n\n\n### Bug Fixes\n\n* **web:** Client decoding incomplete buffer bug ([#1540](https://github.com/hyperium/tonic/issues/1540)) ([83e363a](https://github.com/hyperium/tonic/commit/83e363ace6cbe20ccc2efbe1eb10a4236e4b8065))\n\n\n# [0.10.1](https://github.com/hyperium/tonic/compare/v0.10.0...v0.10.1) (2023-09-21)\n\n### Bug Fixes\n\n* **web:** Buffer incomplete messages ([#1528](https://github.com/hyperium/tonic/issues/1528)) ([fe6f8d9](https://github.com/hyperium/tonic/commit/fe6f8d9b4953a266eb32945a67edce9558bd05b3))\n\n# [0.10.0](https://github.com/hyperium/tonic/compare/v0.9.2...v0.10.0) (2023-09-08)\n\n\n### Bug Fixes\n\n* **codegen:** Use stream type from codegen mod ([#1446](https://github.com/hyperium/tonic/issues/1446)) ([60d776b](https://github.com/hyperium/tonic/commit/60d776b019854b6a6881d69823a36dcc18b1b4ce))\n* **examples:** Use https scheme when using tls ([#1466](https://github.com/hyperium/tonic/issues/1466)) ([388b177](https://github.com/hyperium/tonic/commit/388b177d99e7b0a2c8d5eab1dee65c4dbb671db4))\n* **tls:** Don't use tls w/ `http` scheme ([#1454](https://github.com/hyperium/tonic/issues/1454)) ([95e81f5](https://github.com/hyperium/tonic/commit/95e81f51fbbc32a5cf2b94ac0d7005d56b44a8d3))\n\n\n### Features\n\n* **build:** Add optional default unimplemented stubs ([#1344](https://github.com/hyperium/tonic/issues/1344)) ([aff1daf](https://github.com/hyperium/tonic/commit/aff1daf65d9a0d55b92719318eba2b5a4769c4e1))\n* **core:** amortize many ready messages into fewer, larger buffers ([#1423](https://github.com/hyperium/tonic/issues/1423)) ([76eedc1](https://github.com/hyperium/tonic/commit/76eedc13d0dd891892301afa38c3dd8ae6646edf))\n* **tonic-types:** add ability to extract rich error details from `google.rpc.Status` ([#1430](https://github.com/hyperium/tonic/issues/1430)) ([5fd635a](https://github.com/hyperium/tonic/commit/5fd635a30568ff629c4197c603c45b6b94750e88))\n* **transport:** Add `Router::into_router` ([#1442](https://github.com/hyperium/tonic/issues/1442)) ([ea06a1b](https://github.com/hyperium/tonic/commit/ea06a1bb30bc325c7f6d7763fe48bf8b88c1c3ed))\n* **transport:** Expose TcpConnectInfo fields ([#1449](https://github.com/hyperium/tonic/issues/1449)) ([74b079c](https://github.com/hyperium/tonic/commit/74b079ce752311fbe760d748804d801c385a5e7a))\n* **web:** Add `GrpcWebClientService` ([#1472](https://github.com/hyperium/tonic/issues/1472)) ([dc29c17](https://github.com/hyperium/tonic/commit/dc29c17ae3ef729024e1f80c66566b09d7a01051))\n\n\n\n## [0.9.2](https://github.com/hyperium/tonic/compare/v0.9.1...v0.9.2) (2023-04-17)\n\n\n\n## [0.9.1](https://github.com/hyperium/tonic/compare/v0.9.0...v0.9.1) (2023-04-03)\n\n\n\n# [0.9.0](https://github.com/hyperium/tonic/compare/v0.8.4...v0.9.0) (2023-03-31)\n\n\n### Bug Fixes\n\n* **build:** Allow Services to be named Result ([#1203](https://github.com/hyperium/tonic/issues/1203)) ([a562a3c](https://github.com/hyperium/tonic/commit/a562a3ce329a38696dfcb0d82b7102d93fb30a5c)), closes [#1156](https://github.com/hyperium/tonic/issues/1156)\n* **codec:** Cancelled client streaming handling ([#1315](https://github.com/hyperium/tonic/issues/1315)) ([c8027a1](https://github.com/hyperium/tonic/commit/c8027a1385dd5d3fb6abdce7be49c46a43d4f3c2)), closes [#848](https://github.com/hyperium/tonic/issues/848)\n* MetadataKey::from_bytes returns an error ([#1246](https://github.com/hyperium/tonic/issues/1246)) ([930c805](https://github.com/hyperium/tonic/commit/930c805127cada70e4e4ab03c7680214b5c2a4f5))\n* **web:** Fix `enable` and update docs ([#1326](https://github.com/hyperium/tonic/issues/1326)) ([a9db219](https://github.com/hyperium/tonic/commit/a9db219e50b7d27e48cd44e76941113a36b72e26))\n\n\n### Features\n\n* add GrpcMethod extension into request for client ([#1275](https://github.com/hyperium/tonic/issues/1275)) ([7a6b20d](https://github.com/hyperium/tonic/commit/7a6b20d8ef5d31c9cc01f0cf697df1f3e28cb421))\n* **build:** Builder: add {enum,message}_attributes ([#1234](https://github.com/hyperium/tonic/issues/1234)) ([ff642f9](https://github.com/hyperium/tonic/commit/ff642f9233beab322333745f9edfa9c62ae18ca4))\n* **codec:** Configure max request message size ([#1274](https://github.com/hyperium/tonic/issues/1274)) ([9f716d8](https://github.com/hyperium/tonic/commit/9f716d841184b8521720c6ed941af137ca2ee6a0)), closes [#1097](https://github.com/hyperium/tonic/issues/1097)\n* **core:** Default encoding/decoding limits ([#1335](https://github.com/hyperium/tonic/issues/1335)) ([ff33119](https://github.com/hyperium/tonic/commit/ff331199e45c8b53e93f1bd51ccd74dafc2146ac))\n* **reflection:** Add dummy implementation for extension ([#1209](https://github.com/hyperium/tonic/issues/1209)) ([fdff111](https://github.com/hyperium/tonic/commit/fdff11115b44c4cc7e3de59ea045a193fa6881bc))\n* Rename api related to protobuf ([#1224](https://github.com/hyperium/tonic/issues/1224)) ([d2542dc](https://github.com/hyperium/tonic/commit/d2542dc034e89383bd182a25a0d3235859fb10f9))\n* **tls:** add an option for optional TLS client authentication ([#1163](https://github.com/hyperium/tonic/issues/1163)) ([773e4e1](https://github.com/hyperium/tonic/commit/773e4e1749daf023222f2294816b1f09d9e916a0)), closes [#687](https://github.com/hyperium/tonic/issues/687)\n* **tonic:** Use NamedService without transport feature ([#1273](https://github.com/hyperium/tonic/issues/1273)) ([5acde56](https://github.com/hyperium/tonic/commit/5acde56176d928ffddbf1076e922764fb151f959))\n* **transport:** Add`local_addr` to `Request o` ([#1327](https://github.com/hyperium/tonic/issues/1327)) ([b54ce23](https://github.com/hyperium/tonic/commit/b54ce2321a5cba1c32261f4eda2b27d1110b893d))\n* **transport:** added support for EC keys ([#1145](https://github.com/hyperium/tonic/issues/1145)) ([17d6a4b](https://github.com/hyperium/tonic/commit/17d6a4b576c1571bb149d3e935e9a835265a80dd)), closes [#1143](https://github.com/hyperium/tonic/issues/1143)\n* **types:** Add gRPC Richer Error Model support (Docs) ([#1317](https://github.com/hyperium/tonic/issues/1317)) ([69ce71e](https://github.com/hyperium/tonic/commit/69ce71efa6f4601c9e8060e87d0641a51251e9ab))\n* **types:** Add gRPC Richer Error Model support (Examples) ([#1300](https://github.com/hyperium/tonic/issues/1300)) ([d471212](https://github.com/hyperium/tonic/commit/d471212ee8264ca6c5169a9893f361187e9378c9))\n* **types:** Add gRPC Richer Error Model support (Help) ([#1293](https://github.com/hyperium/tonic/issues/1293)) ([d6041a9](https://github.com/hyperium/tonic/commit/d6041a99c2a216a2ebc83b7bc5a0947ba7ca869c))\n* **types:** Add gRPC Richer Error Model support (LocalizedMessage) ([#1295](https://github.com/hyperium/tonic/issues/1295)) ([d54d02d](https://github.com/hyperium/tonic/commit/d54d02d3ed8bf221c0c54494b7ce692d412391a4))\n* **types:** Add gRPC Richer Error Model support (PreconditionFailure) ([#1276](https://github.com/hyperium/tonic/issues/1276)) ([2378581](https://github.com/hyperium/tonic/commit/2378581850483f26fd7c1dee0a797d936b73e881))\n* **types:** Add gRPC Richer Error Model support (QuotaFailure) ([#1204](https://github.com/hyperium/tonic/issues/1204)) ([03b4735](https://github.com/hyperium/tonic/commit/03b4735bb4ba7c6e84842d0515d1fd3be9d1cc13))\n* **types:** Add gRPC Richer Error Model support (ResourceInfo) ([#1282](https://github.com/hyperium/tonic/issues/1282)) ([7eeda24](https://github.com/hyperium/tonic/commit/7eeda24350c5a61cae7c8e56cc0439d9c40cc77d))\n* **types:** Add gRPC Richer Error Model support (RetryInfo) ([#1095](https://github.com/hyperium/tonic/issues/1095)) ([6cdb3d4](https://github.com/hyperium/tonic/commit/6cdb3d4685966b71f051e4cd67c50e1d2db402f5))\n* **types:** add support for `DebugInfo` error message type ([#1179](https://github.com/hyperium/tonic/issues/1179)) ([3076e82](https://github.com/hyperium/tonic/commit/3076e8251e602ed6e98a8b3029070b33e3459109))\n* **types:** Expose FILE_DESCRIPTOR_SET  ([#1210](https://github.com/hyperium/tonic/issues/1210)) ([cc42d1f](https://github.com/hyperium/tonic/commit/cc42d1f88c39d87b244f863daf4ff625f6ff36df))\n\n\n\n## [0.8.4](https://github.com/hyperium/tonic/compare/v0.8.3...v0.8.4) (2022-11-29)\n\n\n### Bug Fixes\n\n* **build:** Fix CodeGen8uilder typo ([#1165](https://github.com/hyperium/tonic/issues/1165)) ([#1166](https://github.com/hyperium/tonic/issues/1166)) ([c7476ff](https://github.com/hyperium/tonic/commit/c7476fff425b972c7966228fd38a9191e8d2ddc9))\n\n\n\n## [0.8.3](https://github.com/hyperium/tonic/compare/v0.8.2...v0.8.3) (2022-11-28)\n\n\n### Bug Fixes\n\n* do not panic while encoding oversized bodies ([#1142](https://github.com/hyperium/tonic/issues/1142)) ([33e22bb](https://github.com/hyperium/tonic/commit/33e22bbc5ef1b74de82394c3ebfea27382419620)), closes [#1141](https://github.com/hyperium/tonic/issues/1141)\n* **reflection, health:** Remove transport feature ([#1112](https://github.com/hyperium/tonic/issues/1112)) ([7153289](https://github.com/hyperium/tonic/commit/7153289b51f7770cdd00cefeceddacc4cf36df97))\n\n\n### Features\n\n* **build:** Add `build_transport` builder option ([#1130](https://github.com/hyperium/tonic/issues/1130)) ([1f5bc9b](https://github.com/hyperium/tonic/commit/1f5bc9b9d55f814d1cb83de6f43239e275122265))\n* **build:** Add `CodeGenBuilder` ([#1154](https://github.com/hyperium/tonic/issues/1154)) ([c4525ba](https://github.com/hyperium/tonic/commit/c4525ba6ad21cf9db8d1857931f430cbe924aeb5))\n* **build:** Add disable_comments option ([#1127](https://github.com/hyperium/tonic/issues/1127)) ([e188521](https://github.com/hyperium/tonic/commit/e1885211495e63d962bc1d00f9be6eeaab2bb901))\n* Expose `Request#into_parts` and `Request#from_parts` ([#1118](https://github.com/hyperium/tonic/issues/1118)) ([b409ddd](https://github.com/hyperium/tonic/commit/b409ddd478959e239aeef3cb8715cd3ace470a8f))\n* **transport:** add `from_listener` for `TcpIncoming` ([#1093](https://github.com/hyperium/tonic/issues/1093)) ([0b03b30](https://github.com/hyperium/tonic/commit/0b03b30cccc67d517b05587614405d63d942b1bb))\n* **web:** Implement tower::Layer for tonic_web::Config ([#1119](https://github.com/hyperium/tonic/issues/1119)) ([40536dc](https://github.com/hyperium/tonic/commit/40536dc13428f6338610d74f7b45a5f9c87d9335))\n* **web:** Removed Cors impl and replaced with tower-http's CorsLayer ([#1123](https://github.com/hyperium/tonic/issues/1123)) ([a98d719](https://github.com/hyperium/tonic/commit/a98d719fb4b0a88127504a1ab3eb472e842c6b71)), closes [#1122](https://github.com/hyperium/tonic/issues/1122)\n\n\n\n## [0.8.2](https://github.com/hyperium/tonic/compare/v0.8.0...v0.8.2) (2022-09-28)\n\n\n### Bug Fixes\n\n* **transport:** Bump axum for CVE-2022-3212 ([#1088](https://github.com/hyperium/tonic/issues/1088)) ([cddd992](https://github.com/hyperium/tonic/commit/cddd99266682127a3fa0e5d601f56a6346369814))\n\n\n### Features\n\n* add `Result<T>` type alias for `std::result::Result<T, tonic::Status>` ([#1085](https://github.com/hyperium/tonic/issues/1085)) ([56ff45d](https://github.com/hyperium/tonic/commit/56ff45d9a36040c429753d0d118ad980fbfe3eb8))\n* **build:** add `cleanup-markdown` feature flag ([#1086](https://github.com/hyperium/tonic/issues/1086)) ([c1b08df](https://github.com/hyperium/tonic/commit/c1b08dffacb67e13ce7e94a002eee8999ca7c0e5))\n* **tonic:** impl `Clone` for `Status` using `Arc` ([#1076](https://github.com/hyperium/tonic/issues/1076)) ([ee3d0df](https://github.com/hyperium/tonic/commit/ee3d0dfe7556fc7e996764f650ee3351097e7309))\n* **transport:** Expose hyper's H2 adaptive window on server ([#1071](https://github.com/hyperium/tonic/issues/1071)) ([919d28b](https://github.com/hyperium/tonic/commit/919d28b2b96c7c803cec131a9e36e80d2b071701))\n* **types:** Add gRPC Richer Error Model support (BadRequest) ([#1068](https://github.com/hyperium/tonic/issues/1068)) ([3e40d81](https://github.com/hyperium/tonic/commit/3e40d819cfbd3d5e4e078b79e3c95a43d14d489e)), closes [/github.com/hyperium/tonic/pull/1068#discussion_r956117520](https://github.com//github.com/hyperium/tonic/pull/1068/issues/discussion_r956117520)\n\n\n\n# [0.8.0](https://github.com/hyperium/tonic/compare/v0.7.2...v0.8.0) (2022-07-29)\n\n\n### Features\n\n* Add `Grpc::with_origin` for clients ([#1017](https://github.com/hyperium/tonic/issues/1017)) ([10f6d2f](https://github.com/hyperium/tonic/commit/10f6d2f1a9fa3969599ebd674f7be27f4f458754))\n* **build:** Add option to emit rerun-if-changed instructions ([#1021](https://github.com/hyperium/tonic/issues/1021)) ([1d2083a](https://github.com/hyperium/tonic/commit/1d2083a1a690edcb3f95343edfe229339c4257b7))\n* **build:** Better support for custom codecs ([#999](https://github.com/hyperium/tonic/issues/999)) ([de2e4ac](https://github.com/hyperium/tonic/commit/de2e4ac077c076736dc451f3415ea7da1a61a560))\n* Decouple `NamedService` from the `transport` feature ([#969](https://github.com/hyperium/tonic/issues/969)) ([feae96c](https://github.com/hyperium/tonic/commit/feae96c5be1247af368e6ce665c8df757d298e35))\n\n\n### BREAKING CHANGES\n\n* **build:** `CODEC_PATH` moved from const to fn\n\n\n\n## [0.7.2](https://github.com/hyperium/tonic/compare/v0.7.1...v0.7.2) (2022-05-05)\n\n\n### Bug Fixes\n\n* **build:** Reduce `Default` bound requirement ([#974](https://github.com/hyperium/tonic/issues/974)) ([4533a6e](https://github.com/hyperium/tonic/commit/4533a6e20eb889f8f13446c0edf39613fa4fe9f6))\n* don't enable default features in tower ([#972](https://github.com/hyperium/tonic/issues/972)) ([b4f9634](https://github.com/hyperium/tonic/commit/b4f96343afe6106db80f41f49e576a687bfcd633))\n* **transport:** Emit `HttpsUriWithoutTlsSupport` only w/ tls feat ([#996](https://github.com/hyperium/tonic/issues/996)) ([1dd5ad2](https://github.com/hyperium/tonic/commit/1dd5ad2b07810fc6eb5015c152ec737b5f0ca39c))\n\n\n### Features\n\n* Add TryFrom implementations for MetadataValue ([#990](https://github.com/hyperium/tonic/issues/990)) ([edc5a0d](https://github.com/hyperium/tonic/commit/edc5a0d88d4a392effe065dfcc1c005b6bb55b5d))\n\n\n\n## [0.7.1](https://github.com/hyperium/tonic/compare/v0.7.0...v0.7.1) (2022-04-04)\n\n\n### Features\n\n* **transport:** Add `channel` feature flag ([#960](https://github.com/hyperium/tonic/issues/960)) ([f1ca90f](https://github.com/hyperium/tonic/commit/f1ca90f2882925c30f96ef60ccfd4fe39bc2c93b))\n\n\n\n# [0.7.0](https://github.com/hyperium/tonic/compare/v0.6.2...v0.7.0) (2022-04-01)\n\n\n### Bug Fixes\n\n* **build:** clippy warning for must_use ([#892](https://github.com/hyperium/tonic/issues/892)) ([a337f13](https://github.com/hyperium/tonic/commit/a337f132a57dfcc262b70537cf31686519e0f73c))\n* **codec:** Remove `Default` bound on `Codec` ([#894](https://github.com/hyperium/tonic/issues/894)) ([d574cfd](https://github.com/hyperium/tonic/commit/d574cfda3a692d300db02f486a1792a99b3f9f6d))\n* **codec:** Return None after poll_data error ([#921](https://github.com/hyperium/tonic/issues/921)) ([d7cae70](https://github.com/hyperium/tonic/commit/d7cae702fc2284473846db7c946baf87977b7b48))\n* Handle interceptor errors as responses ([#840](https://github.com/hyperium/tonic/issues/840)) ([#842](https://github.com/hyperium/tonic/issues/842)) ([bf44940](https://github.com/hyperium/tonic/commit/bf44940f9b73709a83b31e4595a3d8ad262797a3))\n* **health:** Correctly implement spec for overall health ([#897](https://github.com/hyperium/tonic/issues/897)) ([2b0ffee](https://github.com/hyperium/tonic/commit/2b0ffee62034f5983f8d6dcdafccd66f780559f2))\n* Return error on non https uri instead of panic ([#838](https://github.com/hyperium/tonic/issues/838)) ([ef6e245](https://github.com/hyperium/tonic/commit/ef6e245180936097e56f5f95ed8b182674f3131b))\n* **tonic:** Expose h2 error instead of reason ([#883](https://github.com/hyperium/tonic/issues/883)) ([a33e15a](https://github.com/hyperium/tonic/commit/a33e15a387a6ca1844748346904d28cb4caae84b))\n* **tonic:** Preserve HTTP method in interceptor ([#912](https://github.com/hyperium/tonic/issues/912)) ([e623562](https://github.com/hyperium/tonic/commit/e6235623c4707f97e9b9f7c3ba88745050a884e5))\n* **transport:** connect w/ connector infailable ([#922](https://github.com/hyperium/tonic/issues/922)) ([a197c20](https://github.com/hyperium/tonic/commit/a197c20469a666164c5cba280679e55b9e9e2b6c))\n* **transport:** Endpoint returns transport error ([#920](https://github.com/hyperium/tonic/issues/920)) ([ee6e726](https://github.com/hyperium/tonic/commit/ee6e726707a6839c6cabe672eb296c6118a2a1cd))\n* **transport:** Make `Server::layer()` support more than one layer ([#932](https://github.com/hyperium/tonic/issues/932)) ([e30bb7e](https://github.com/hyperium/tonic/commit/e30bb7ede7e107a3181cd786533c250ba09a2fcf))\n* **transport:** Make server builder more consitient ([#901](https://github.com/hyperium/tonic/issues/901)) ([6763d19](https://github.com/hyperium/tonic/commit/6763d191d267c1b9f861b96ad0f4b850e0264f4d))\n* **web:** Fix error tonic-web doc url ([#928](https://github.com/hyperium/tonic/issues/928)) ([37cd483](https://github.com/hyperium/tonic/commit/37cd48304f07adf09ab61b74b6ba3c91a24d2729))\n\n\n### Features\n\n* **build:** add constructor `from_arc` for gRPC servers ([#875](https://github.com/hyperium/tonic/issues/875)) ([7179f7a](https://github.com/hyperium/tonic/commit/7179f7ae6a5186bb64e4c120302084f56c053206))\n* **build:** Expose Prost generation plugin ([#947](https://github.com/hyperium/tonic/issues/947)) ([d4bd475](https://github.com/hyperium/tonic/commit/d4bd4758dd80135f89d3e559c5d7f42ccbbab504))\n* **build:** use prettyplease to format output ([#890](https://github.com/hyperium/tonic/issues/890)) ([#904](https://github.com/hyperium/tonic/issues/904)) ([d6c0fc1](https://github.com/hyperium/tonic/commit/d6c0fc112b2288a080fd0a727453b24d666e3d79))\n* **health:** Expose `HealthService` publically ([#930](https://github.com/hyperium/tonic/issues/930)) ([097e7e8](https://github.com/hyperium/tonic/commit/097e7e85a9079bb76bef54921f03c6f7e0ee0744))\n* Implement hash for `Code` ([#917](https://github.com/hyperium/tonic/issues/917)) ([6bc7dab](https://github.com/hyperium/tonic/commit/6bc7dab8e099c8ce226a6261e545d8d131c604f0))\n* **tls:** upgrade to tokio-rustls 0.23 (rustls 0.20) ([#859](https://github.com/hyperium/tonic/issues/859)) ([4548997](https://github.com/hyperium/tonic/commit/4548997080c9c34f12dc0ff83ab0e2bb35ceca9c))\n* **transport:** add unix socket support in server ([#861](https://github.com/hyperium/tonic/issues/861)) ([dee2ab5](https://github.com/hyperium/tonic/commit/dee2ab52ff4a2995156a3baf5ea916b479fd1d14))\n* **transport:** port router to axum ([#830](https://github.com/hyperium/tonic/issues/830)) ([6dfc20e](https://github.com/hyperium/tonic/commit/6dfc20e1db455be12b0a647533c65bbfd6ae78f2))\n* **transport:** support customizing `Channel`'s async executor ([#935](https://github.com/hyperium/tonic/issues/935)) ([0859d82](https://github.com/hyperium/tonic/commit/0859d82e577fb024e39ce9b5b7356b95dcb66562))\n* Update prost to 0.10 ([#948](https://github.com/hyperium/tonic/issues/948)) ([c78274e](https://github.com/hyperium/tonic/commit/c78274e3fe5763cba291a605979cd7175ad6c38f))\n\n\n\n## [0.6.2](https://github.com/hyperium/tonic/compare/v0.6.1...v0.6.2) (2021-12-08)\n\n\n### Bug Fixes\n\n* **examples:** Fix autoreload example ([#798](https://github.com/hyperium/tonic/issues/798)) ([#818](https://github.com/hyperium/tonic/issues/818)) ([8508f36](https://github.com/hyperium/tonic/commit/8508f369c2c12b09bcd6c099a7915566603911fd))\n\n\n\n## [0.6.1](https://github.com/hyperium/tonic/compare/v0.6.0...v0.6.1) (2021-10-27)\n\n\n### Bug Fixes\n\n* **transport:** Bump hyper to 0.14.14 ([#813](https://github.com/hyperium/tonic/issues/813)) ([2a3e9b2](https://github.com/hyperium/tonic/commit/2a3e9b2f6fa459b065c5a4ebeab5f447a3515707))\n\n\n\n# [0.6.0](https://github.com/hyperium/tonic/compare/v0.5.2...v0.6.0) (2021-10-25)\n\n\n### Bug Fixes\n\n* **build:** Correctly convert `Empty` to `()` ([#734](https://github.com/hyperium/tonic/issues/734)) ([ff6a690](https://github.com/hyperium/tonic/commit/ff6a690cec9daca33984cabea66f9d370ac63462))\n* **build:** split path types in compile ([#721](https://github.com/hyperium/tonic/issues/721)) ([53ecc1f](https://github.com/hyperium/tonic/commit/53ecc1f85e7f7eeb0dce4ab23432d6c36d8a46b0))\n* **tonic:** change `connect_lazy` to be infallible ([#712](https://github.com/hyperium/tonic/issues/712)) ([2e47154](https://github.com/hyperium/tonic/commit/2e471548d89be98d26b2332d059a24a3fc15ec23))\n* **tonic:** fix extensions disappearing during streaming requests ([5c1bb90](https://github.com/hyperium/tonic/commit/5c1bb90ce82ecf90843a7c959edd7ef8fc280f62)), closes [#770](https://github.com/hyperium/tonic/issues/770)\n* **tonic:** Remove `Sync` requirement for streams ([#804](https://github.com/hyperium/tonic/issues/804)) ([23c1392](https://github.com/hyperium/tonic/commit/23c1392fb7e0ac50bcdedc35509917061bc858e1))\n* **tonic:** Status code to set correct source on unkown error ([#799](https://github.com/hyperium/tonic/issues/799)) ([4054d61](https://github.com/hyperium/tonic/commit/4054d61e14b9794a72b48de1a051c26129ec36b1))\n* **transport:** AddOrigin panic on invalid uri ([#801](https://github.com/hyperium/tonic/issues/801)) ([3ab00f3](https://github.com/hyperium/tonic/commit/3ab00f304dd204fccf00d1995e635fa6b2f8503b))\n* **transport:** Correctly map hyper errors ([#629](https://github.com/hyperium/tonic/issues/629)) ([4947b07](https://github.com/hyperium/tonic/commit/4947b076f5b0b5149ee7f6144515535b85f65db5))\n\n\n### Features\n\n* **build:** Support prost's include_file option ([#774](https://github.com/hyperium/tonic/issues/774)) ([3f9ab80](https://github.com/hyperium/tonic/commit/3f9ab801f7ee50ec04ab0f73cd457898dc687e61))\n* Update `prost` and friends to 0.9 ([#791](https://github.com/hyperium/tonic/issues/791)) ([09805ec](https://github.com/hyperium/tonic/commit/09805ece453047bf609b1a69c72931eae6e1144a))\n\n\n\n## [0.5.2](https://github.com/hyperium/tonic/compare/v0.5.1...v0.5.2) (2021-08-10)\n\n\n\n## [0.5.1](https://github.com/hyperium/tonic/compare/v0.5.0...v0.5.1) (2021-08-09)\n\n\n### Bug Fixes\n\n* **build:** allow services to be named `Service` ([#709](https://github.com/hyperium/tonic/issues/709)) ([380d81d](https://github.com/hyperium/tonic/commit/380d81dd86a4d4ab2a23a7d9c072eab67631c331))\n* **build:** remove unnecessary `Debug` constraint for client streams ([#719](https://github.com/hyperium/tonic/issues/719)) ([167e8cb](https://github.com/hyperium/tonic/commit/167e8cb5b212338b0d668f5304ab19823ab94529))\n\n\n### Features\n\n* **examples:** add grpc-web example ([#710](https://github.com/hyperium/tonic/issues/710)) ([5aa8ae1](https://github.com/hyperium/tonic/commit/5aa8ae1fec27377cd4c2a41d309945d7e38087d0))\n* **health:** Expose grpc_health_v1 file descriptor set ([#620](https://github.com/hyperium/tonic/issues/620)) ([6ee638d](https://github.com/hyperium/tonic/commit/6ee638d9409144dc1c587283f47994ba9f4b8efd))\n* **tonic:** add `Interceptor` trait ([#713](https://github.com/hyperium/tonic/issues/713)) ([8c8f4d1](https://github.com/hyperium/tonic/commit/8c8f4d12515643050f47227894c98e226b01f924))\n* **transport:** Add `Connected` impl for `DuplexStream` ([#722](https://github.com/hyperium/tonic/issues/722)) ([0e33a02](https://github.com/hyperium/tonic/commit/0e33a0241e642b402a2215d30a8bfc0de2b168d2))\n\n\n\n# [0.5.0](https://github.com/hyperium/tonic/compare/v0.4.3...v0.5.0) (2021-07-08)\n\n\n### Bug Fixes\n\n* **build:** fix `with_interceptor` not building on Rust 1.51 ([#669](https://github.com/hyperium/tonic/issues/669)) ([9478fac](https://github.com/hyperium/tonic/commit/9478fac97984cf8291bf89c55eb9a02a06889e03))\n* **codec:** Fix streaming reponses w/ many status ([#689](https://github.com/hyperium/tonic/issues/689)) ([737ace3](https://github.com/hyperium/tonic/commit/737ace393d3d11fb179af939e5f1a5d16ebc2b82)), closes [#681](https://github.com/hyperium/tonic/issues/681)\n* **codec:** improve error message for invalid compression flag ([#663](https://github.com/hyperium/tonic/issues/663)) ([9cc14b7](https://github.com/hyperium/tonic/commit/9cc14b79fba9e789e215f7ea3fa40ccfaecc8e59))\n* **examples:** Fix tower examples ([#624](https://github.com/hyperium/tonic/issues/624)) ([4a917a3](https://github.com/hyperium/tonic/commit/4a917a32f05c70c99d608be5ae3fc58f130ee4df))\n* **tonic:** don't include error's cause in Display impl ([#633](https://github.com/hyperium/tonic/issues/633)) ([31a3468](https://github.com/hyperium/tonic/commit/31a34681c7ba606e27615859d4b65dfcdcaa6f38))\n* **tonic:** don't remove reserved headers in interceptor ([#701](https://github.com/hyperium/tonic/issues/701)) ([6711b80](https://github.com/hyperium/tonic/commit/6711b8067457ed31f1844e3ec6571ef0c4589325))\n* **tonic:** make `Interceptor` `UnwindSafe` ([#641](https://github.com/hyperium/tonic/issues/641)) ([57509d3](https://github.com/hyperium/tonic/commit/57509d321ba49e6e9189efef345d59089875dff8))\n* **transport:** remove needless `BoxFuture` ([#644](https://github.com/hyperium/tonic/issues/644)) ([74ad0a9](https://github.com/hyperium/tonic/commit/74ad0a998fedb2507f6b2f035b961eb9bac5b494))\n* **web:** fix compilation ([#670](https://github.com/hyperium/tonic/issues/670)) ([e199387](https://github.com/hyperium/tonic/commit/e1993877c430906500aeda9ab1e3413e68ed483d))\n\n\n### Features\n\n* **build:** support adding attributes to clients and servers ([#684](https://github.com/hyperium/tonic/issues/684)) ([a948a8f](https://github.com/hyperium/tonic/commit/a948a8f884705b9f2a6df5c86d07cc6eb0bb1b7c))\n* **codec:** compression support ([#692](https://github.com/hyperium/tonic/issues/692)) ([0583cff](https://github.com/hyperium/tonic/commit/0583cff80f57ba071295416ee8828c3430851d0d))\n* **metadata:** expose `IterMut` and `ValuesMut` ([#639](https://github.com/hyperium/tonic/issues/639)) ([b0ec3ea](https://github.com/hyperium/tonic/commit/b0ec3ead344df44fc17e5ad22398ed2464768e63))\n* **metadata:** remove manual `Send + Sync` impls for metadata types ([#640](https://github.com/hyperium/tonic/issues/640)) ([e97f518](https://github.com/hyperium/tonic/commit/e97f5180250a567aead16fe9a8644216edc4bbb3))\n* **tonic-web:** implement grpc <-> grpc-web protocol translation ([#455](https://github.com/hyperium/tonic/issues/455)) ([c309063](https://github.com/hyperium/tonic/commit/c309063254dff42fd05afc5e56b0b0371b905758))\n* **tonic:** add `h2::Error` as a `source` for `Status` ([#612](https://github.com/hyperium/tonic/issues/612)) ([b90bb7b](https://github.com/hyperium/tonic/commit/b90bb7bbc012207451fe2788a8efd69023312425))\n* **tonic:** add `Request` and `Response` extensions ([#642](https://github.com/hyperium/tonic/issues/642)) ([352b0f5](https://github.com/hyperium/tonic/commit/352b0f584be33bc49ca266698c9224d16a6825ff))\n* **tonic:** expose setting for `http2_adaptive_window` ([#657](https://github.com/hyperium/tonic/issues/657)) ([12815d0](https://github.com/hyperium/tonic/commit/12815d0a1d558eb9f661a85354336b04df1f5bab))\n* **tonic:** implement `From<Code>` for `i32` ([f33316d](https://github.com/hyperium/tonic/commit/f33316d5b32f6a44fa23ea12851f502c48bac5ea))\n* **tonic:** make it easier to add tower middleware to servers ([#651](https://github.com/hyperium/tonic/issues/651)) ([4d2667d](https://github.com/hyperium/tonic/commit/4d2667d1cb1b938756d20dafa3cccae1db23a831))\n* **tonic:** pass `trace_fn` the request rather than just the headers ([#634](https://github.com/hyperium/tonic/issues/634)) ([7862a22](https://github.com/hyperium/tonic/commit/7862a2259db8dc1af440604c6c582487a59a2709))\n* **tonic:** Use `BoxBody` from `http-body` crate ([#622](https://github.com/hyperium/tonic/issues/622)) ([4dda4cb](https://github.com/hyperium/tonic/commit/4dda4cbcca88fa46a7d8a6e4eabfb6d7c333617a))\n* **transport:** Add `connect_with_connector_lazy` ([#696](https://github.com/hyperium/tonic/issues/696)) ([2a46ff5](https://github.com/hyperium/tonic/commit/2a46ff5c96415b217700353dadba74a80e5ad88c)), closes [#695](https://github.com/hyperium/tonic/issues/695)\n* **transport:** Add a tls-webpki-roots feature to add trust roots from webpki-roots ([#660](https://github.com/hyperium/tonic/issues/660)) ([32173dc](https://github.com/hyperium/tonic/commit/32173dc7f6521bad8f26b055b6a86d807348f151))\n* **transport:** add connect timeout to `Endpoint` ([#662](https://github.com/hyperium/tonic/issues/662)) ([2b60a00](https://github.com/hyperium/tonic/commit/2b60a00614c5c4260ce0acaaa599da89bebfd267))\n* **transport:** provide generic access to connect info ([#647](https://github.com/hyperium/tonic/issues/647)) ([e5e3118](https://github.com/hyperium/tonic/commit/e5e311853bff347355722bc829d40f54e8954aee))\n\n\n\n## [0.4.3](https://github.com/hyperium/tonic/compare/v0.4.2...v0.4.3) (2021-04-29)\n\n\n### Features\n\n* **tonic:** Add `Request::set_timeout` ([#615](https://github.com/hyperium/tonic/issues/615)) ([dae31d0](https://github.com/hyperium/tonic/commit/dae31d0e1cfafaaad9d634d7c0022c65ab76d7e1))\n* **transport:** Support timeouts with \"grpc-timeout\" header ([#606](https://github.com/hyperium/tonic/issues/606)) ([9ff4f7b](https://github.com/hyperium/tonic/commit/9ff4f7b8e418278a923a86bb925e3f3e189ca7e0))\n\n\n\n## [0.4.2](https://github.com/hyperium/tonic/compare/v0.4.1...v0.4.2) (2021-04-13)\n\n\n### Bug Fixes\n\n* **codec:** Allocate inbound buffer once ([#578](https://github.com/hyperium/tonic/issues/578)) ([1d2754f](https://github.com/hyperium/tonic/commit/1d2754feba6b49bfc813f41e8e8e42ffaf8ab0dd))\n* **reflection:** Depend on correct version of build ([#582](https://github.com/hyperium/tonic/issues/582)) ([db09093](https://github.com/hyperium/tonic/commit/db0909382b8ab1a385c1352feeea663844b7d799))\n\n\n### Features\n\n* **build:** Add `prostoc_args` ([#577](https://github.com/hyperium/tonic/issues/577)) ([480a794](https://github.com/hyperium/tonic/commit/480a79409c4cb9a1c680e57d0f74ad1d4f18beaa))\n* Expose status constructors ([#579](https://github.com/hyperium/tonic/issues/579)) ([0d05aa0](https://github.com/hyperium/tonic/commit/0d05aa0d02bd3037e81c72dcf7fa5168d5a62097))\n* **health:** Expose proto and client ([#471](https://github.com/hyperium/tonic/issues/471)) ([#602](https://github.com/hyperium/tonic/issues/602)) ([49f6137](https://github.com/hyperium/tonic/commit/49f613767341656cad1cc4883ff0e89b03d378ae))\n\n\n### Reverts\n\n* Revert \"Remove grpc-timeout header from reserved headers (#603)\" ([7aaa2f8](https://github.com/hyperium/tonic/commit/7aaa2f85d991d875673825fd76931d0a4f3c86b0)), closes [#603](https://github.com/hyperium/tonic/issues/603)\n\n\n\n## [0.4.1](https://github.com/hyperium/tonic/compare/v0.4.0...v0.4.1) (2021-03-16)\n\n\n### Bug Fixes\n\n* Depend on at least tower 0.4.4 ([#554](https://github.com/hyperium/tonic/issues/554)) ([ca3b9a1](https://github.com/hyperium/tonic/commit/ca3b9a1df12f32a425926a6cd7d04e1692f8f503)), closes [#553](https://github.com/hyperium/tonic/issues/553) [#552](https://github.com/hyperium/tonic/issues/552) [#553](https://github.com/hyperium/tonic/issues/553) [#552](https://github.com/hyperium/tonic/issues/552)\n\n\n### Features\n\n* **build:** Add disable_package_emission option to tonic-build ([#556](https://github.com/hyperium/tonic/issues/556)) ([4f5e160](https://github.com/hyperium/tonic/commit/4f5e160679bf1ac37c7d3094a65690ce59986fc3))\n* **build:** Support compiling well-known protobuf types ([#522](https://github.com/hyperium/tonic/issues/522)) ([61555ff](https://github.com/hyperium/tonic/commit/61555ff2b5b76e4e3172717354aed1e6f31d6611))\n* **build:** Use `RUSTFMT` to find `rustfmt` binary ([#566](https://github.com/hyperium/tonic/issues/566)) ([ea56e2e](https://github.com/hyperium/tonic/commit/ea56e2e2b89d45c95c60152cbe5e4338e1c997fd))\n* Implement gRPC Reflection Service ([#340](https://github.com/hyperium/tonic/issues/340)) ([c54f247](https://github.com/hyperium/tonic/commit/c54f24721c669f0784694568f387bba6bec98e12))\n\n\n\n# [0.4.0](https://github.com/hyperium/tonic/compare/v0.3.1...v0.4.0) (2021-01-15)\n\n\n### Bug Fixes\n\n* **build:** Add content-type for generated unimplemented service ([#441](https://github.com/hyperium/tonic/issues/441)) ([62c1230](https://github.com/hyperium/tonic/commit/62c1230117bcaa6f45cb0fa0697b89b9255a94a5))\n* **build:** Match namespace code with other generated packages ([#472](https://github.com/hyperium/tonic/issues/472)) ([1b03ece](https://github.com/hyperium/tonic/commit/1b03ece2a81cb7e8b1922b3c3c1f496bd402d76c))\n* gracefully handle bad native certs ([#520](https://github.com/hyperium/tonic/issues/520)) ([fe4d5b9](https://github.com/hyperium/tonic/commit/fe4d5b9d9a0fdcf414bbe31c2fcad59e8cc03da8)), closes [#519](https://github.com/hyperium/tonic/issues/519)\n* **transport:** Add content-type for Unimplemented ([#434](https://github.com/hyperium/tonic/issues/434)) ([594a542](https://github.com/hyperium/tonic/commit/594a542b8a9e8f9f4c3bd1d0a08e87ce74a850e5))\n* **transport:** reconnect lazy connections after first failure ([#458](https://github.com/hyperium/tonic/issues/458)) ([e9910d1](https://github.com/hyperium/tonic/commit/e9910d10a7c1287a2247a236b45dbf31eceb08bd)), closes [#452](https://github.com/hyperium/tonic/issues/452)\n* **transport:** return Poll::ready until error is consumed  ([#536](https://github.com/hyperium/tonic/issues/536)) ([dafea9a](https://github.com/hyperium/tonic/commit/dafea9adeec5626ee780bc3ad7dc69691db51a82))\n\n\n* fix(transport) Do not panic when building and Endpoint with an invali… (#438) ([26ce9d1](https://github.com/hyperium/tonic/commit/26ce9d12bf1765e5a7acb07cab05b6bd75bd4e4d)), closes [#438](https://github.com/hyperium/tonic/issues/438)\n\n\n### Features\n\n* **tonic:** implement From<io::Error> for Status ([#500](https://github.com/hyperium/tonic/issues/500)) ([fc86563](https://github.com/hyperium/tonic/commit/fc86563b369d0b73a79d3e8dc9a84d5ce1513303))\n* **transport:** Add `Router::into_service` ([#419](https://github.com/hyperium/tonic/issues/419)) ([37f6733](https://github.com/hyperium/tonic/commit/37f6733f85a42e828c124026c3a0f21919549b12))\n* **transport:** add max http2 frame size to server. ([#529](https://github.com/hyperium/tonic/issues/529)) ([31936e0](https://github.com/hyperium/tonic/commit/31936e0513a41e83c8137786bd417fe57ecd05eb)), closes [#264](https://github.com/hyperium/tonic/issues/264)\n* **transport:** add user-agent header to client requests. ([#457](https://github.com/hyperium/tonic/issues/457)) ([d4899df](https://github.com/hyperium/tonic/commit/d4899df83287a4eb1a91754c2e2955000d13c5f4)), closes [#453](https://github.com/hyperium/tonic/issues/453)\n* **transport:** Connect lazily in the load balanced channel ([#493](https://github.com/hyperium/tonic/issues/493)) ([2e964c7](https://github.com/hyperium/tonic/commit/2e964c78c666ecd6e6cfc37689d30300cad81f4c))\n* **transport:** expose HTTP2 server keepalive interval and timeout ([#486](https://github.com/hyperium/tonic/issues/486)) ([2b9cdb9](https://github.com/hyperium/tonic/commit/2b9cdb9779eb5cb7d3862e1ce95ab63f847ec223)), closes [#474](https://github.com/hyperium/tonic/issues/474)\n* **transport:** Fix TLS accept w/ peer certs ([#535](https://github.com/hyperium/tonic/issues/535)) ([41c51f1](https://github.com/hyperium/tonic/commit/41c51f1c61ac957e439ced4302f09160c850787e))\n* **transport:** Move error! to debug! ([#537](https://github.com/hyperium/tonic/issues/537)) ([a7778ad](https://github.com/hyperium/tonic/commit/a7778ad16611b7ade64c33256eecf9825408f06a))\n\n\n### BREAKING CHANGES\n\n* `TryFrom` API has been changed.\n\n\n\n## [0.3.1](https://github.com/hyperium/tonic/compare/v0.3.0...v0.3.1) (2020-08-20)\n\n\n### Bug Fixes\n\n* **transport:** Return connection error on `Channel::connect` ([#413](https://github.com/hyperium/tonic/issues/413)) ([2ea17b2](https://github.com/hyperium/tonic/commit/2ea17b2ecfc40a20f4d9608f807b3d099a8f415d)), closes [#403](https://github.com/hyperium/tonic/issues/403)\n\n\n\n# [0.3.0](https://github.com/hyperium/tonic/compare/v0.2.1...v0.3.0) (2020-07-13)\n\n\n### Bug Fixes\n\n* `Status::details` leaking base64 encoding ([#395](https://github.com/hyperium/tonic/issues/395)) ([2c4c544](https://github.com/hyperium/tonic/commit/2c4c544d902c588fc0654910fba1f0d21d78eab3)), closes [#379](https://github.com/hyperium/tonic/issues/379)\n* **build:** Allow empty packages ([#382](https://github.com/hyperium/tonic/issues/382)) ([f085aba](https://github.com/hyperium/tonic/commit/f085aba302001986fd04219d2843f659f73c4031)), closes [#381](https://github.com/hyperium/tonic/issues/381)\n* **build:** Make generated server service public ([#347](https://github.com/hyperium/tonic/issues/347)) ([8cd6f05](https://github.com/hyperium/tonic/commit/8cd6f0506429cfbe59e63b0216f208482d12358a))\n* Remove uses of pin_project::project attribute ([#367](https://github.com/hyperium/tonic/issues/367)) ([5bda615](https://github.com/hyperium/tonic/commit/5bda6156328bd2c94bc274588871b666f1b72d6e))\n* **transport:** Propagate errors in tls_config instead of unwrap/panic ([#385](https://github.com/hyperium/tonic/issues/385)) ([3b9d6a6](https://github.com/hyperium/tonic/commit/3b9d6a6262b62f30b8c9953f0da8e403be53216e))\n\n\n### Features\n\n* Add `Display` implementation for `Code` ([#386](https://github.com/hyperium/tonic/issues/386)) ([ab1de44](https://github.com/hyperium/tonic/commit/ab1de44771f3fa6ac283485bdbf1035d6407ac1a))\n* Add `Status::to_http` ([#376](https://github.com/hyperium/tonic/issues/376)) ([327b4ff](https://github.com/hyperium/tonic/commit/327b4fffa3381345ee4620df7e9998efe2aa9454))\n* Add metadata to error responses ([#348](https://github.com/hyperium/tonic/issues/348)) ([372da52](https://github.com/hyperium/tonic/commit/372da52e96114ca76cc221f3c598be82bfae970c))\n* add new method get_uri for Endpoint ([#371](https://github.com/hyperium/tonic/issues/371)) ([54d7a7a](https://github.com/hyperium/tonic/commit/54d7a7af6b6530b80353c5741586c38cca8382c9))\n* **codec:** Improve compression flag log ([#374](https://github.com/hyperium/tonic/issues/374)) ([d68dd36](https://github.com/hyperium/tonic/commit/d68dd365321764aceaf4e37a106a519797926495))\n* **transport:** Add Endpoint::connect_lazy method ([#392](https://github.com/hyperium/tonic/issues/392)) ([ec9046d](https://github.com/hyperium/tonic/commit/ec9046dfc23d63828363d9555cd7b96811ad442d)), closes [#167](https://github.com/hyperium/tonic/issues/167)\n* **transport:** Add optional service methods ([#275](https://github.com/hyperium/tonic/issues/275)) ([2b997b0](https://github.com/hyperium/tonic/commit/2b997b0c5f37d69f3cd8b5b566b64df110d9f4eb))\n* **transport:** Dynamic load balancing ([#341](https://github.com/hyperium/tonic/issues/341)) ([85ae0a4](https://github.com/hyperium/tonic/commit/85ae0a4733b9e99edaa05e65160d98f21f288fc1))\n* **types:** Add `tonic-types` crate ([#391](https://github.com/hyperium/tonic/issues/391)) ([ea7fe66](https://github.com/hyperium/tonic/commit/ea7fe66b145e01891f1c1f16d247e02524d98fae))\n\n\n\n## [0.2.1](https://github.com/hyperium/tonic/compare/v0.2.0...v0.2.1) (2020-05-07)\n\n\n### Bug Fixes\n\n* base64 encode details header ([#345](https://github.com/hyperium/tonic/issues/345)) ([e683ffe](https://github.com/hyperium/tonic/commit/e683ffef1fcbe0ace9cc696232489f5f6600e83f))\n* **build:** Remove ambiguity in service method call ([#327](https://github.com/hyperium/tonic/issues/327)) ([5d56daa](https://github.com/hyperium/tonic/commit/5d56daa721cfb18edc74cf50db4270e2c8461fc9))\n* **transport:** Apply tls-connector for discovery when applicable ([#334](https://github.com/hyperium/tonic/issues/334)) ([#338](https://github.com/hyperium/tonic/issues/338)) ([99fbe22](https://github.com/hyperium/tonic/commit/99fbe22e7c1340d6be9ee5d3ae9738850881af61))\n\n\n### Features\n\n* **transport:** Add AsRef impl for Certificate ([#326](https://github.com/hyperium/tonic/issues/326)) ([d2ad8df](https://github.com/hyperium/tonic/commit/d2ad8df629a349cc151a0a4ede96f04356f73839))\n\n\n\n# [0.2.0](https://github.com/hyperium/tonic/compare/v0.1.1...v0.2.0) (2020-04-01)\n\n\n### Bug Fixes\n\n* **build:** Allow non_camel_case_types on codegen structs ([224280d](https://github.com/hyperium/tonic/commit/224280dfff8944e9e553337416d23d6e5a050945)), closes [#295](https://github.com/hyperium/tonic/issues/295)\n* **build:** Don't replace extern_paths ([#261](https://github.com/hyperium/tonic/issues/261)) ([1b3d107](https://github.com/hyperium/tonic/commit/1b3d107206136312a2536d3b72748c52191d99b1))\n* **build:** Ignore non `.rs` files with rustfmt ([#284](https://github.com/hyperium/tonic/issues/284)) ([7dfa2a2](https://github.com/hyperium/tonic/commit/7dfa2a277b593e008cea53eef7163ca59a06c56a)), closes [#283](https://github.com/hyperium/tonic/issues/283)\n* **build:** Implement Debug for client struct ([6dbe88d](https://github.com/hyperium/tonic/commit/6dbe88d445e378fff48d05083c23baeb2020cb2d)), closes [#298](https://github.com/hyperium/tonic/issues/298)\n* **build:** Remove debug println! ([#287](https://github.com/hyperium/tonic/issues/287)) ([e2c2be2](https://github.com/hyperium/tonic/commit/e2c2be2f084b7c1ef4e93f6994cb9c728de0c1ed))\n* **build:** Server service uses generic body bound ([#306](https://github.com/hyperium/tonic/issues/306)) ([5758b75](https://github.com/hyperium/tonic/commit/5758b758b2d44059b0149a31542d11589999a789))\n* **health:** Set referenced version of tonic ([59c7788](https://github.com/hyperium/tonic/commit/59c77888464a0302993dbe07fed7c1848b415f8f))\n* **metadata:** Remove deprecated error description ([61e0429](https://github.com/hyperium/tonic/commit/61e0429ae810354363835c36a046b5113b3c74b4))\n* **transport:** Handle tls accepting on task ([#320](https://github.com/hyperium/tonic/issues/320)) ([04a8c0c](https://github.com/hyperium/tonic/commit/04a8c0c82a4007f48c3bf3539a3f2312746fedd1))\n\n\n### Features\n\n* Add Status with Details Constructor ([#308](https://github.com/hyperium/tonic/issues/308)) ([cfd59db](https://github.com/hyperium/tonic/commit/cfd59dbb342a8b7d216f4856e13d24b564c606f3))\n* **build:** Add support for custom prost config ([#318](https://github.com/hyperium/tonic/issues/318)) ([202093c](https://github.com/hyperium/tonic/commit/202093c31715b52997c6c206c758924ff5f69bc8))\n* **build:** Decouple codgen from `prost` ([#170](https://github.com/hyperium/tonic/issues/170)) ([f65cda1](https://github.com/hyperium/tonic/commit/f65cda1ea0a190fe07c4f8d91473baad9a6f1f77))\n* **health:** Add tonic-health server impl ([da92dbf](https://github.com/hyperium/tonic/commit/da92dbf8aa885ea0ea05755e9432532fc980e353)), closes [#135](https://github.com/hyperium/tonic/issues/135) [#135](https://github.com/hyperium/tonic/issues/135)\n* **transport:** Expose http2 keep-alive support ([#307](https://github.com/hyperium/tonic/issues/307)) ([012fa3c](https://github.com/hyperium/tonic/commit/012fa3cb4a0e010dafa28305416fab6c4278fc7b))\n\n\n\n## [0.1.1](https://github.com/hyperium/tonic/compare/v0.1.0...v0.1.1) (2020-01-20)\n\n\n### Bug Fixes\n\n* **build:** Typo with client mod docstring ([#237](https://github.com/hyperium/tonic/issues/237)) ([5fc6762](https://github.com/hyperium/tonic/commit/5fc6762435494d8df023bea8e35a5d20d81f2f3b))\n* **transport:** Add Connected impl for TcpStream ([#245](https://github.com/hyperium/tonic/issues/245)) ([cfdf0af](https://github.com/hyperium/tonic/commit/cfdf0aff549196af0c3b7f6e531dbeacfb6990dc))\n* **transport:** Use Uri host if no domain for tls ([#244](https://github.com/hyperium/tonic/issues/244)) ([6de0b4d](https://github.com/hyperium/tonic/commit/6de0b4d26fd82b4d1303080b0ba8c4db2d4f0fd1))\n\n\n\n# [0.1.0](https://github.com/hyperium/tonic/compare/v0.1.0-beta.1...v0.1.0) (2020-01-14)\n\n\n### Bug Fixes\n\n* **build:** Remove default impl for Server traits ([#229](https://github.com/hyperium/tonic/issues/229)) ([a41f55a](https://github.com/hyperium/tonic/commit/a41f55ab9dfe77fca920b3c2e89343c7ce963225))\n* **transport:** Improve `Error` type ([#217](https://github.com/hyperium/tonic/issues/217)) ([ec1f37e](https://github.com/hyperium/tonic/commit/ec1f37e4b46279d20f4fadafa5bf30cfb729fa42))\n\n\n### chore\n\n* rename ServiceName -> NamedService ([#233](https://github.com/hyperium/tonic/issues/233)) ([6ee2ed9](https://github.com/hyperium/tonic/commit/6ee2ed9b4ff30c0517d70908c6348a633dab5b91))\n\n\n### Features\n\n* Add gRPC interceptors ([#232](https://github.com/hyperium/tonic/issues/232)) ([eba7ec7](https://github.com/hyperium/tonic/commit/eba7ec7b32fb96938cbdc3d2dfd91c238afda0dc))\n* **build:** Add extern_path config support ([#223](https://github.com/hyperium/tonic/issues/223)) ([e034288](https://github.com/hyperium/tonic/commit/e034288c3739467238aee54fdbe0a2a3a87bf824))\n* **codec:** Introduce `Decoder/Encoder` traits ([#208](https://github.com/hyperium/tonic/issues/208)) ([0fa2bf1](https://github.com/hyperium/tonic/commit/0fa2bf1cea9d1166d49e40f2211268611b6993de))\n* **transport:** Add `serve_with_incoming_shutdown` ([#220](https://github.com/hyperium/tonic/issues/220)) ([a66595b](https://github.com/hyperium/tonic/commit/a66595bfe3c146daaa437bddd5ce3db4542b1bf6))\n* **transport:** Add server side peer cert support ([#228](https://github.com/hyperium/tonic/issues/228)) ([af807c3](https://github.com/hyperium/tonic/commit/af807c3ccd283cee0e424e75298cd176424767ca))\n\n\n### BREAKING CHANGES\n\n* Rename `ServiceName` to `NamedService`.\n* removed `interceptor_fn` and `intercep_headers_fn` from `transport` in favor of using `tonic::Interceptor`.\n* **codec:** Add new `Decoder/Encoder` traits and use `EncodeBuf/DecodeBuf` over `BytesMut` directly.\n* **build:** remove default implementations for server traits.\n\n\n\n# [0.1.0-beta.1](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.5...v0.1.0-beta.1) (2019-12-19)\n\n\n### Bug Fixes\n\n* **build:** Allow creating multiple services in the same package ([#173](https://github.com/hyperium/tonic/issues/173)) ([0847b67](https://github.com/hyperium/tonic/commit/0847b67c4eb66a814c8c447a57fade2552e64a85))\n* **build:** Prevent duplicated client/server generated code ([#121](https://github.com/hyperium/tonic/issues/121)) ([b02b4b2](https://github.com/hyperium/tonic/commit/b02b4b238bfee96b886609396b957e2592477ecb))\n* **build:** Remove async ready ([#185](https://github.com/hyperium/tonic/issues/185)) ([97d5363](https://github.com/hyperium/tonic/commit/97d5363e2b2aee456edc5db4b5b53316c8b40745))\n* **build:** snake_case service names ([#190](https://github.com/hyperium/tonic/issues/190)) ([3a5c66d](https://github.com/hyperium/tonic/commit/3a5c66d5f236eaece05dbd9fd1e1a00a3ab98259))\n* **docs:** typo in lib.rs ([#142](https://github.com/hyperium/tonic/issues/142)) ([c63c107](https://github.com/hyperium/tonic/commit/c63c107560db165303c369487006b3507a0e7e07))\n* **examples:** Remove use of VecDeque as a placeholder type ([#143](https://github.com/hyperium/tonic/issues/143)) ([354d4fd](https://github.com/hyperium/tonic/commit/354d4fdc35dc51575f4c685fc04354f2058061ff))\n* Sanitize custom metadata ([#138](https://github.com/hyperium/tonic/issues/138)) ([f9502df](https://github.com/hyperium/tonic/commit/f9502dfd7ef306fff86c83b711bc96623555ef5c))\n* **transport:** Fix infinite recursion in `poll_ready` ([#192](https://github.com/hyperium/tonic/issues/192)) ([c99d13c](https://github.com/hyperium/tonic/commit/c99d13c6e669be3a6ecf428ae32d4b937393738a)), closes [#184](https://github.com/hyperium/tonic/issues/184) [#191](https://github.com/hyperium/tonic/issues/191)\n* **transport:** Fix lazily reconnecting ([#187](https://github.com/hyperium/tonic/issues/187)) ([0505dff](https://github.com/hyperium/tonic/commit/0505dff65a18c162c3ae398d42ed20ac54351439)), closes [#167](https://github.com/hyperium/tonic/issues/167)\n* **transport:** Load balance connecting panic ([#128](https://github.com/hyperium/tonic/issues/128)) ([23e7695](https://github.com/hyperium/tonic/commit/23e7695800d8f22ee8e0ba7456f5ffc4b19430c3)), closes [#127](https://github.com/hyperium/tonic/issues/127)\n* **transport:** Remove support for OpenSSL ([#141](https://github.com/hyperium/tonic/issues/141)) ([8506050](https://github.com/hyperium/tonic/commit/85060500f3a8f91ed47c632e07896c9e5567629a))\n* **transport:** Remove with_rustls for tls config ([#188](https://github.com/hyperium/tonic/issues/188)) ([502491a](https://github.com/hyperium/tonic/commit/502491a59031dc0aa6e51a764f8edab04ab85581))\n* **transport:** Update builders to move self ([#132](https://github.com/hyperium/tonic/issues/132)) ([85ef18f](https://github.com/hyperium/tonic/commit/85ef18f8b7f91047ca5bcfe5fc90e3c510c7936a))\n\n\n### Features\n\n* Add `Status` constructors ([#137](https://github.com/hyperium/tonic/issues/137)) ([997241c](https://github.com/hyperium/tonic/commit/997241c43fdb390caad19a41dc6bf67724de521a))\n* expose tcp_nodelay for clients and servers ([#145](https://github.com/hyperium/tonic/issues/145)) ([0eb9991](https://github.com/hyperium/tonic/commit/0eb9991b9fcd4a688904788966d1e5ab74918571))\n* **transport:** Add `remote_addr` to `Request` on the server si… ([#186](https://github.com/hyperium/tonic/issues/186)) ([3eb76ab](https://github.com/hyperium/tonic/commit/3eb76abf9fdce5f903de1a7f05b8afc8694fa0ce))\n* **transport:** Add server graceful shutdown ([#169](https://github.com/hyperium/tonic/issues/169)) ([393a57e](https://github.com/hyperium/tonic/commit/393a57eadebb8e2e6d3633f70141edba647b5f65))\n* **transport:** Add system root anchors for TLS ([#114](https://github.com/hyperium/tonic/issues/114)) ([ac0e333](https://github.com/hyperium/tonic/commit/ac0e333b39f60f9c304d7798a49e07e9f08a16d4)), closes [#101](https://github.com/hyperium/tonic/issues/101)\n* **transport:** Add tracing support to server ([#175](https://github.com/hyperium/tonic/issues/175)) ([f46a454](https://github.com/hyperium/tonic/commit/f46a45401d42f6c8b6ab449f7462735a9aea0bfc))\n* **transport:** Allow custom IO and UDS example ([#184](https://github.com/hyperium/tonic/issues/184)) ([b90c340](https://github.com/hyperium/tonic/commit/b90c3408001f762a32409f7e2cf688ebae39d89e)), closes [#136](https://github.com/hyperium/tonic/issues/136)\n* **transport:** Enable TCP_NODELAY. ([#120](https://github.com/hyperium/tonic/issues/120)) ([0299509](https://github.com/hyperium/tonic/commit/029950904a5e1398bb508446b660c1863e9f631c))\n* **transport:** Expose tcp keepalive to clients & servers ([#151](https://github.com/hyperium/tonic/issues/151)) ([caccfad](https://github.com/hyperium/tonic/commit/caccfad7e7b03d42aa1679c00a270c92a621bb0f))\n\n\n### BREAKING CHANGES\n\n* **build:** Build will now generate each service client and server into their own modules.\n* **transport:** Remove support for OpenSSL within the transport.\n\n\n\n# [0.1.0-alpha.5](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.4...v0.1.0-alpha.5) (2019-10-31)\n\n\n### Bug Fixes\n\n* **build:** Fix missing argument in generate_connect ([#95](https://github.com/hyperium/tonic/issues/95)) ([eea3c0f](https://github.com/hyperium/tonic/commit/eea3c0f99ac292efb7b8d4956fa014108af871ac))\n* **codec:** Enforce encoders/decoders are `Sync` ([#84](https://github.com/hyperium/tonic/issues/84)) ([3ce61d9](https://github.com/hyperium/tonic/commit/3ce61d9860528dd4a13f719774d5c649198fb55c)), closes [#81](https://github.com/hyperium/tonic/issues/81)\n* **codec:** Remove custom content-type  ([#104](https://github.com/hyperium/tonic/issues/104)) ([a17049f](https://github.com/hyperium/tonic/commit/a17049f1f72c9655a72fef8021072d56b3f4e543))\n\n\n### Features\n\n* Add `IntoRequest` and `IntoStreamingRequest` traits ([#66](https://github.com/hyperium/tonic/issues/66)) ([4bb087b](https://github.com/hyperium/tonic/commit/4bb087b5ff19636a20e10a669ba3b46f99c84358))\n* **transport:** Add service multiplexing/routing ([#99](https://github.com/hyperium/tonic/issues/99)) ([5b4f468](https://github.com/hyperium/tonic/commit/5b4f4689a253ccca34f34bb5329b420efb9159c1)), closes [#29](https://github.com/hyperium/tonic/issues/29)\n* **transport:** Change channel connect to be async ([#107](https://github.com/hyperium/tonic/issues/107)) ([5c2f4db](https://github.com/hyperium/tonic/commit/5c2f4dba322b28e8132b21acfa184309de791d12))\n\n\n### BREAKING CHANGES\n\n* **transport:** `Endpoint::channel` was removed in favor of\nan async `Endpoint::connect`.\n\n\n\n# [0.1.0-alpha.4](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.3...v0.1.0-alpha.4) (2019-10-23)\n\n\n### Bug Fixes\n\n* **build:** Fix service and rpc name conflict ([#92](https://github.com/hyperium/tonic/issues/92)) ([1dbde95](https://github.com/hyperium/tonic/commit/1dbde95d844378121af54f16d9f8aa9f0f7fc2f2)), closes [#89](https://github.com/hyperium/tonic/issues/89)\n* **client:** Use `Stream` instead of `TrySteam` for client calls ([#61](https://github.com/hyperium/tonic/issues/61)) ([7eda823](https://github.com/hyperium/tonic/commit/7eda823c9cbe6054c39b42f8f3e7efce4698aebe))\n* **codec:** Properly decode partial DATA frames ([#83](https://github.com/hyperium/tonic/issues/83)) ([9079e0f](https://github.com/hyperium/tonic/commit/9079e0f66bc75d2ce49a5537bf66c9ff5effbdab))\n* **transport:** Rename server tls config method ([#73](https://github.com/hyperium/tonic/issues/73)) ([2a4bdb2](https://github.com/hyperium/tonic/commit/2a4bdb24f62bb3bbceb73e9551ba70512f94c187))\n\n\n### Features\n\n* **docs:** Add routeguide tutorial ([#21](https://github.com/hyperium/tonic/issues/21)) ([5d0a795](https://github.com/hyperium/tonic/commit/5d0a7955541509d2dbfdb9b689fb57cd2b842172))\n* **transport:** Add support client mTLS ([#77](https://github.com/hyperium/tonic/issues/77)) ([335a373](https://github.com/hyperium/tonic/commit/335a373a403615a9737b2e19d0089c89bcaa3c4e))\n\n\n### BREAKING CHANGES\n\n* **transport:** `rustls_client_config` for the server has been renamed to `rustls_server_config`.\n\n\n\n# [0.1.0-alpha.3](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.2...v0.1.0-alpha.3) (2019-10-09)\n\n\n### Features\n\n* **build:** Expose prost-build type_attributes and field_attribu… ([#60](https://github.com/hyperium/tonic/issues/60)) ([06ff619](https://github.com/hyperium/tonic/commit/06ff619944a2f44d3aea60e653b39157c392f541))\n* **transport:** Expose more granular control of TLS configuration ([#48](https://github.com/hyperium/tonic/issues/48)) ([8db3961](https://github.com/hyperium/tonic/commit/8db3961491c35955c76bf2da6a17bf8a60e3b146))\n\n\n\n# [0.1.0-alpha.2](https://github.com/hyperium/tonic/compare/2670b349f96666c8d30d9d5d6ac2e611bb4584e2...v0.1.0-alpha.2) (2019-10-08)\n\n\n### Bug Fixes\n\n* **codec:** Fix buffer decode panic on full ([#43](https://github.com/hyperium/tonic/issues/43)) ([ed3e7e9](https://github.com/hyperium/tonic/commit/ed3e7e95a5401b9b224640e17908c2182286197d))\n* **codegen:** Fix Empty protobuf type and add unimplemented ([#26](https://github.com/hyperium/tonic/issues/26)) ([2670b34](https://github.com/hyperium/tonic/commit/2670b349f96666c8d30d9d5d6ac2e611bb4584e2))\n* **codegen:** Use wellknown types from `prost-types` ([#49](https://github.com/hyperium/tonic/issues/49)) ([4e1fcec](https://github.com/hyperium/tonic/commit/4e1fcece150fb1f373b0ccbb69d302463ed6bcfd))\n* **transport:** Attempt to load RSA private keys in rustls ([#39](https://github.com/hyperium/tonic/issues/39)) ([2c5c3a2](https://github.com/hyperium/tonic/commit/2c5c3a282a1ccc9288bc0f6fb138fc123f45dd09))\n* **transport:** Avoid exit after bad TLS handshake ([#51](https://github.com/hyperium/tonic/issues/51)) ([412a0bd](https://github.com/hyperium/tonic/commit/412a0bd697b4822b94c55cb18d2373a6ed75b690))\n\n\n### Features\n\n* **codgen:** Add default implementations for the generated serve… ([#27](https://github.com/hyperium/tonic/issues/27)) ([4559613](https://github.com/hyperium/tonic/commit/4559613c37f75dde67981ee38a7f5af5947ef0be))\n* **transport:** Expose http/2 settings ([#28](https://github.com/hyperium/tonic/issues/28)) ([0218d58](https://github.com/hyperium/tonic/commit/0218d58c282d6de6f300229677c99369d3ea20ed))\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Tonic\n\n:balloon: Thanks for your help improving the project! We are so happy to have\nyou!\n\nThere are opportunities to contribute to `tonic` at any level. It doesn't\nmatter if you are just getting started with Rust or are the most weathered\nexpert, we can use your help.\n\n**No contribution is too small and all contributions are valued.**\n\nThis guide will help you get started. **Do not let this guide intimidate you**.\nIt should be considered a map to help you navigate the process.\n\nYou may also get help with contributing in the `dev` channel, please join\nus!\n\nTonic is a part of the [Tokio][tokio] and [Hyperium][hyperium] project, and follows the project's\nguidelines for contributing. This document is based on the\n[`CONTRIBUTING.md` file][tokio-contrib] in the `tokio-rs/tokio` repository.\n\n[dev]: https://gitter.im/tokio-rs/dev\n[tokio]: https://tokio.rs\n[hyperium]: https://github.com/hyperium\n[tokio-contrib]: https://github.com/tokio-rs/tokio/blob/master/CONTRIBUTING.md\n\n## Conduct\n\nThe `tonic` project adheres to the [Rust Code of Conduct][coc]. This describes\nthe _minimum_ behavior expected from all contributors.\n\n[coc]: https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md\n\n## Contributing in Issues\n\nFor any issue, there are fundamentally three ways an individual can contribute:\n\n1. By opening the issue for discussion: For instance, if you believe that you\n   have uncovered a bug in a `tonic` crate, creating a new issue in the\n   hyperium/tonic [issue tracker][issues] is the way to report it.\n\n2. By helping to triage the issue: This can be done by providing\n   supporting details (a test case that demonstrates a bug), providing\n   suggestions on how to address the issue, or ensuring that the issue is tagged\n   correctly.\n\n3. By helping to resolve the issue: Typically this is done either in the form of\n   demonstrating that the issue reported is not a problem after all, or more\n   often, by opening a Pull Request that changes some bit of something in\n   Tokio in a concrete and reviewable manner.\n\n**Anybody can participate in any stage of contribution**. We urge you to\nparticipate in the discussion around bugs and participate in reviewing PRs.\n\n[issues]: https://github.com/hyperium/tonic/issues\n\n### Asking for General Help\n\nIf you have reviewed existing documentation and still have questions or are\nhaving problems, you can open an issue asking for help.\n\nIn exchange for receiving help, we ask that you contribute back a documentation\nPR that helps others avoid the problems that you encountered.\n\n### Submitting a Bug Report\n\nWhen opening a new issue in the `tonic` issue tracker, users will\nbe presented with a [basic template][template] that should be filled in. If you\nbelieve that you have uncovered a bug, please fill out this form, following the\ntemplate to the best of your ability. Do not worry if you cannot answer every\ndetail, just fill in what you can.\n\nThe two most important pieces of information we need in order to properly\nevaluate the report is a description of the behavior you are seeing and a simple\ntest case we can use to recreate the problem on our own. If we cannot recreate\nthe issue, it becomes impossible for us to fix.\n\nIn order to rule out the possibility of bugs introduced by userland code, test\ncases should be limited, as much as possible, to using only Tokio APIs.\n\nSee [How to create a Minimal, Complete, and Verifiable example][mcve].\n\n[mcve]: https://stackoverflow.com/help/mcve\n[template]: .github/ISSUE_TEMPLATE/bug_report.md\n\n### Triaging a Bug Report\n\nOnce an issue has been opened, it is not uncommon for there to be discussion\naround it. Some contributors may have differing opinions about the issue,\nincluding whether the behavior being seen is a bug or a feature. This discussion\nis part of the process and should be kept focused, helpful, and professional.\n\nShort, clipped responses—that provide neither additional context nor supporting\ndetail—are not helpful or professional. To many, such responses are simply\nannoying and unfriendly.\n\nContributors are encouraged to help one another make forward progress as much as\npossible, empowering one another to solve issues collaboratively. If you choose\nto comment on an issue that you feel either is not a problem that needs to be\nfixed, or if you encounter information in an issue that you feel is incorrect,\nexplain why you feel that way with additional supporting context, and be willing\nto be convinced that you may be wrong. By doing so, we can often reach the\ncorrect outcome much faster.\n\n### Resolving a Bug Report\n\nIn the majority of cases, issues are resolved by opening a Pull Request. The\nprocess for opening and reviewing a Pull Request is similar to that of opening\nand triaging issues, but carries with it a necessary review and approval\nworkflow that ensures that the proposed changes meet the minimal quality and\nfunctional guidelines of the Tokio project.\n\n## Pull Requests\n\nPull Requests are the way concrete changes are made to the code, documentation,\nand dependencies in the `tonic` repository.\n\nEven tiny pull requests (e.g., one character pull request fixing a typo in API\ndocumentation) are greatly appreciated. Before making a large change, it is\nusually a good idea to first open an issue describing the change to solicit\nfeedback and guidance. This will increase the likelihood of the PR getting\nmerged.\n\n### Tests\n\nIf the change being proposed alters code (as opposed to only documentation for\nexample), it is either adding new functionality to a crate or it is fixing\nexisting, broken functionality. In both of these cases, the pull request should\ninclude one or more tests to ensure that the crate does not regress in the future.\nThere are two ways to write tests: integration tests and documentation tests\n(Tokio avoids unit tests as much as possible).\n\n#### Integration tests\n\nIntegration tests go in the same crate as the code they are testing. Each sub\ncrate should have a `dev-dependency` on `tonic` itself. This makes all\n`tonic` utilities available to use in tests, no matter the crate being\ntested.\n\nThe best strategy for writing a new integration test is to look at existing\nintegration tests in the crate and follow the style.\n\n#### Documentation tests\n\nIdeally, every API has at least one [documentation test] that demonstrates how to\nuse the API. Documentation tests are run with `cargo test --doc`. This ensures\nthat the example is correct and provides additional test coverage.\n\nThe trick to documentation tests is striking a balance between being succinct\nfor a reader to understand and actually testing the API.\n\nThe type level example for `tokio_timer::Timeout` provides a good example of a\ndocumentation test:\n\n```rust\n/// // import the `timeout` function, usually this is done\n/// // with `use tokio::prelude::*`\n/// use tokio::prelude::FutureExt;\n/// use futures::Stream;\n/// use futures::sync::mpsc;\n/// use std::time::Duration;\n///\n/// # fn main() {\n/// let (tx, rx) = mpsc::unbounded();\n/// # tx.unbounded_send(()).unwrap();\n/// # drop(tx);\n///\n/// let process = rx.for_each(|item| {\n///     // do something with `item`\n/// # drop(item);\n/// # Ok(())\n/// });\n///\n/// # tokio::runtime::current_thread::block_on_all(\n/// // Wrap the future with a `Timeout` set to expire in 10 milliseconds.\n/// process.timeout(Duration::from_millis(10))\n/// # ).unwrap();\n/// # }\n```\n\nGiven that this is a *type* level documentation test and the primary way users\nof `tokio` will create an instance of `Timeout` is by using\n`FutureExt::timeout`, this is how the documentation test is structured.\n\nLines that start with `/// #` are removed when the documentation is generated.\nThey are only there to get the test to run. The `block_on_all` function is the\neasiest way to execute a future from a test.\n\nIf this were a documentation test for the `Timeout::new` function, then the\nexample would explicitly use `Timeout::new`. For example:\n\n```rust\n/// use tokio::timer::Timeout;\n/// use futures::Future;\n/// use futures::sync::oneshot;\n/// use std::time::Duration;\n///\n/// # fn main() {\n/// let (tx, rx) = oneshot::channel();\n/// # tx.send(()).unwrap();\n///\n/// # tokio::runtime::current_thread::block_on_all(\n/// // Wrap the future with a `Timeout` set to expire in 10 milliseconds.\n/// Timeout::new(rx, Duration::from_millis(10))\n/// # ).unwrap();\n/// # }\n```\n\n#### Generated code\n\nWhen making changes to `tonic-build` that affects the generated code you will\nneed to ensure that each of the sub crates gets updated as well. Each of the sub\ncrates like, for example `tonic-health`, generate their gRPC code via `codegen`\ncrate.\n\n```\ncargo run --package codegen\n```\n\n### Commits\n\nIt is a recommended best practice to keep your changes as logically grouped as\npossible within individual commits. There is no limit to the number of commits\nany single Pull Request may have, and many contributors find it easier to review\nchanges that are split across multiple commits.\n\nThat said, if you have a number of commits that are \"checkpoints\" and don't\nrepresent a single logical change, please squash those together.\n\nNote that multiple commits often get squashed when they are landed (see the\nnotes about [commit squashing]).\n\n#### Commit message guidelines\n\nA good commit message should describe what changed and why.\n\n1. The first line should:\n\n  * contain a short description of the change (preferably 50 characters or less,\n    and no more than 72 characters)\n  * be entirely in lowercase with the exception of proper nouns, acronyms, and\n    the words that refer to code, like function/variable names\n  * be prefixed with the name of the crate being changed (without the\n    `tonic` prefix) and start with an imperative verb.\n\n  Examples:\n\n  * build: add regex for parsing field filters\n  * tonic: add `Clone` impl for `Service` and `MakeService`\n\n2. Keep the second line blank.\n3. Wrap all other lines at 72 columns (except for long URLs).\n4. If your patch fixes an open issue, you can add a reference to it at the end\n   of the log. Use the `Fixes: #` prefix and the issue number. For other\n   references use `Refs: #`. `Refs` may include multiple issues, separated by a\n   comma.\n\n   Examples:\n\n   - `Fixes: #1337`\n   - `Refs: #1234`\n\nSample complete commit message:\n\n```txt\nsubcrate: explain the commit in one line\n\nBody of commit message is a few lines of text, explaining things\nin more detail, possibly giving some background about the issue\nbeing fixed, etc.\n\nThe body of the commit message can be several paragraphs, and\nplease do proper word-wrap and keep columns shorter than about\n72 characters or so. That way, `git log` will show things\nnicely even when it is indented.\n\nFixes: #1337\nRefs: #453, #154\n```\n\n### Opening the Pull Request\n\nFrom within GitHub, opening a new Pull Request will present you with a\n[template] that should be filled out. Please try to do your best at filling out\nthe details, but feel free to skip parts if you're not sure what to put.\n\n[template]: .github/PULL_REQUEST_TEMPLATE.md\n\n### Discuss and update\n\nYou will probably get feedback or requests for changes to your Pull Request.\nThis is a big part of the submission process so don't be discouraged! Some\ncontributors may sign off on the Pull Request right away, others may have\nmore detailed comments or feedback. This is a necessary part of the process\nin order to evaluate whether the changes are correct and necessary.\n\n**Any community member can review a PR and you might get conflicting feedback**.\nKeep an eye out for comments from code owners to provide guidance on conflicting\nfeedback.\n\n**Once the PR is open, do not rebase the commits**. See [Commit Squashing] for\nmore details.\n\n### Commit Squashing\n\nIn most cases, **do not squash commits that you add to your Pull Request during\nthe review process**. When the commits in your Pull Request land, they may be\nsquashed into one commit per logical change. Metadata will be added to the\ncommit message (including links to the Pull Request, links to relevant issues,\nand the names of the reviewers). The commit history of your Pull Request,\nhowever, will stay intact on the Pull Request page.\n\n## Reviewing Pull Requests\n\n**Any Tokio and Hyperium community member is welcome to review any pull request**.\n\nAll Tokio contributors who choose to review and provide feedback on Pull\nRequests have a responsibility to both the project and the individual making the\ncontribution. Reviews and feedback must be helpful, insightful, and geared\ntowards improving the contribution as opposed to simply blocking it. If there\nare reasons why you feel the PR should not land, explain what those are. Do not\nexpect to be able to block a Pull Request from advancing simply because you say\n\"No\" without giving an explanation. Be open to having your mind changed. Be open\nto working with the contributor to make the Pull Request better.\n\nReviews that are dismissive or disrespectful of the contributor or any other\nreviewers are strictly counter to the Code of Conduct.\n\nWhen reviewing a Pull Request, the primary goals are for the codebase to improve\nand for the person submitting the request to succeed. **Even if a Pull Request\ndoes not land, the submitters should come away from the experience feeling like\ntheir effort was not wasted or unappreciated**. Every Pull Request from a new\ncontributor is an opportunity to grow the community.\n\n### Review a bit at a time.\n\nDo not overwhelm new contributors.\n\nIt is tempting to micro-optimize and make everything about relative performance,\nperfect grammar, or exact style matches. Do not succumb to that temptation.\n\nFocus first on the most significant aspects of the change:\n\n1. Does this change make sense for Tokio?\n2. Does this change make Tokio better, even if only incrementally?\n3. Are there clear bugs or larger scale issues that need attending to?\n4. Is the commit message readable and correct? If it contains a breaking change\n   is it clear enough?\n\nNote that only **incremental** improvement is needed to land a PR. This means\nthat the PR does not need to be perfect, only better than the status quo. Follow\nup PRs may be opened to continue iterating.\n\nWhen changes are necessary, *request* them, do not *demand* them, and **do not\nassume that the submitter already knows how to add a test or run a benchmark**.\n\nSpecific performance optimization techniques, coding styles and conventions\nchange over time. The first impression you give to a new contributor never does.\n\nNits (requests for small changes that are not essential) are fine, but try to\navoid stalling the Pull Request. Most nits can typically be fixed by the Tokio\nCollaborator landing the Pull Request but they can also be an opportunity for\nthe contributor to learn a bit more about the project.\n\nIt is always good to clearly indicate nits when you comment: e.g.\n`Nit: change foo() to bar(). But this is not blocking.`\n\nIf your comments were addressed but were not folded automatically after new\ncommits or if they proved to be mistaken, please, [hide them][hiding-a-comment]\nwith the appropriate reason to keep the conversation flow concise and relevant.\n\n### Be aware of the person behind the code\n\nBe aware that *how* you communicate requests and reviews in your feedback can\nhave a significant impact on the success of the Pull Request. Yes, we may land\na particular change that makes `tonic` better, but the individual might\njust not want to have anything to do with `tonic` ever again. The goal is\nnot just having good code.\n\n### Abandoned or Stalled Pull Requests\n\nIf a Pull Request appears to be abandoned or stalled, it is polite to first\ncheck with the contributor to see if they intend to continue the work before\nchecking if they would mind if you took it over (especially if it just has nits\nleft). When doing so, it is courteous to give the original contributor credit\nfor the work they started (either by preserving their name and email address in\nthe commit log, or by using an `Author: ` meta-data tag in the commit.\n\n_Adapted from the [Node.js contributing guide][node]_.\n\n[node]: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md\n[hiding-a-comment]: https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment\n[documentation test]: https://doc.rust-lang.org/rustdoc/documentation-tests.html\n\n## Releasing\n\nSince the Tonic project consists of a number of crates, many of which depend on\neach other, releasing new versions to crates.io can involve some complexities.\nWhen releasing a new version of a crate, follow these steps:\n\n1. First you must pick the correct version to release, if there are breaking\n   changes make sure to select a semver compatible version bump.\n\n2. In general, tonic tries to keep all crates at the same version to make it\n   easy to release and figure out what sub crates you need that will work with\n   the core version of tonic. To prepare a release branch you can follow the\n   commands below:\n   ```\n   git checkout -b <release-branch-name>\n   ./prepare-release.sh <version> # where version is X.Y.Z \n   ```\n\n3. Once all the crate versions have been updated its time to update the\n   changelog. Tonic uses `conventional-changelog` and it's cli to generate the\n   changelog.\n\n   ```\n   conventional-changelog -p angular -i CHANGELOG.md -s\n   ```\n\n   Once the entries have been generated, you must edit the `CHANGELOG.md` file\n   to add the version and tag to the title and edit any changelog entries. You\n   must also add any breaking changes here as sometimes they get lost.\n\n4. Once the changelog has been updated you can now create a `chore: release\n   vX.Y.Z` commit and push the release branch and open a release PR.\n\n5. Once the release PR has been approved and merged into `master` the following\n   command will release those changes.\n\n   ```\n   ./publish-release.sh\n   ```\n\n6. Once all the crates have been released you now must create a release on\n   github using the text from the changelog.\n\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n  \"tonic\",\n  \"tonic-build\",\n  \"tonic-health\",\n  \"tonic-protobuf\",\n  \"tonic-protobuf-build\",\n  \"tonic-types\",\n  \"tonic-reflection\",\n  \"tonic-prost\",\n  \"tonic-prost-build\",\n  \"tonic-web\",\n  \"examples\",\n  \"codegen\",\n  \"grpc\",\n  \"xds-client\",\n  \"tonic-xds\",\n  \"interop\",\n  \"tests/disable_comments\",\n  \"tests/wellknown\",\n  \"tests/wellknown-compiled\",\n  \"tests/extern_path/uuid\",\n  \"tests/extern_path/my_application\",\n  \"tests/integration_tests\",\n  \"tests/compression\",\n  \"tests/compile\",\n  \"tests/web\",\n  \"tests/default_stubs\",\n  \"tests/deprecated_methods\",\n]\nresolver = \"2\"\n\n[workspace.package]\nrust-version = \"1.88\"\n\n[workspace.lints.rust]\nmissing_debug_implementations = \"warn\"\nmissing_docs = \"warn\"\nrust_2018_idioms = \"warn\"\nunreachable_pub = \"warn\"\n\n[workspace.lints.clippy]\nuninlined_format_args = \"deny\"\n\n[workspace.lints.rustdoc]\nbroken_intra_doc_links = \"deny\"\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2025 Lucio Franco\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![](https://github.com/hyperium/tonic/raw/master/.github/assets/tonic-banner.svg?sanitize=true)\n\n\nA rust implementation of [gRPC], a high performance, open source, general\nRPC framework that puts mobile and HTTP/2 first.\n\n> **Note**: tonic's [master](https://github.com/hyperium/tonic) branch is\n> currently preparing breaking changes. For the most recently *released* code,\n> look to the [0.14.x branch](https://github.com/hyperium/tonic/tree/v0.14.x).\n\n[`tonic`] is a gRPC over HTTP/2 implementation focused on high performance, interoperability, and flexibility. This library was created to have first class support of async/await and to act as a core building block for production systems written in Rust.\n\n[![Crates.io](https://img.shields.io/crates/v/tonic)](https://crates.io/crates/tonic)\n[![Documentation](https://docs.rs/tonic/badge.svg)](https://docs.rs/tonic)\n[![Crates.io](https://img.shields.io/crates/l/tonic)](LICENSE)\n\n\n[Examples] | [Website] | [Docs] | [Chat][discord]\n\n## Overview\n\n[`tonic`] is composed of three main components: the generic gRPC implementation, the high performance HTTP/2\nimplementation and the codegen powered by [`prost`]. The generic implementation can support any HTTP/2\nimplementation and any encoding via a set of generic traits. The HTTP/2 implementation is based on [`hyper`],\na fast HTTP/1.1 and HTTP/2 client and server built on top of the robust [`tokio`] stack. The codegen\ncontains the tools to build clients and servers from [`protobuf`] definitions.\n\n## Features\n\n- Bi-directional streaming\n- High performance async io\n- Interoperability\n- TLS backed by [`rustls`]\n- Load balancing\n- Custom metadata\n- Authentication\n- Health Checking\n\n## Getting Started\n\n- The [`helloworld`][helloworld-tutorial] tutorial provides a basic example of using `tonic`, perfect for first time users!\n- The [`routeguide`][routeguide-tutorial] tutorial provides a complete example of using `tonic` and all its features.\n\nExamples can be found in [`examples`] and for more complex scenarios [`interop`]\nmay be a good resource as it shows examples of many of the gRPC features.\n\n### Rust Version\n\n`tonic`'s MSRV is `1.88`.\n\n### Dependencies\n\n[`tonic-build`] uses `protoc` [Protocol Buffers compiler] in some APIs which compile Protocol Buffers resource files such as [`tonic_build::compile_protos()`].\n\n[Protocol Buffers compiler]: https://protobuf.dev/downloads/\n[`tonic_build::compile_protos()`]: https://docs.rs/tonic-build/latest/tonic_build/fn.compile_protos.html\n\n## Getting Help\n\nFirst, see if the answer to your question can be found in the API documentation.\nIf the answer is not there, there is an active community in\nthe [Tonic Discord channel][discord]. We would be happy to try to answer your\nquestion. If that doesn't work, try opening an [issue] with the question.\n\n[issue]: https://github.com/hyperium/tonic/issues/new/choose\n\n## Project Layout\n\n- [`tonic`]: Generic gRPC and HTTP/2 client/server implementation.\n- [`tonic-build`]: [`prost`] based service codegen.\n- [`tonic-types`]: [`prost`] based grpc utility types including support for gRPC Well Known Types.\n- [`tonic-health`]: Implementation of the standard [gRPC health checking service][healthcheck].\n  Also serves as an example of both unary and response streaming.\n- [`tonic-reflection`]: A tonic based gRPC reflection implementation.\n- [`examples`]: Example gRPC implementations showing off tls, load balancing and bi-directional streaming.\n- [`interop`]: Interop tests implementation.\n\n## Contributing\n\n:balloon: Thanks for your help improving the project! We are so happy to have\nyou! We have a [contributing guide][guide] to help you get involved in the Tonic\nproject.\n\n[guide]: CONTRIBUTING.md\n\n## License\n\nThis project is licensed under the [MIT license](LICENSE).\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in Tonic by you, shall be licensed as MIT, without any additional\nterms or conditions.\n\n\n[gRPC]: https://grpc.io\n[`tonic`]: ./tonic\n[`tonic-build`]: ./tonic-build\n[`tonic-types`]: ./tonic-types\n[`tonic-health`]: ./tonic-health\n[`tonic-reflection`]: ./tonic-reflection\n[`examples`]: ./examples\n[`interop`]: ./interop\n[`tokio`]: https://github.com/tokio-rs/tokio\n[`hyper`]: https://github.com/hyperium/hyper\n[`prost`]: https://github.com/tokio-rs/prost\n[`protobuf`]: https://protobuf.dev/\n[`rustls`]: https://github.com/rustls/rustls\n[`interop`]: https://github.com/hyperium/tonic/tree/master/interop\n[Examples]: https://github.com/hyperium/tonic/tree/master/examples\n[Website]: https://github.com/hyperium/tonic\n[Docs]: https://docs.rs/tonic\n[discord]: https://discord.gg/6yGkFeN\n[routeguide-tutorial]: https://github.com/hyperium/tonic/blob/master/examples/routeguide-tutorial.md\n[helloworld-tutorial]: https://github.com/hyperium/tonic/blob/master/examples/helloworld-tutorial.md\n[healthcheck]: https://grpc.io/docs/guides/health-checking/\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\ntonic (and related projects in hyperium) uses the same security policy as the [Tokio project][tokio-security].\n\n## Report a security issue\n\nThe process for reporting an issue is the same as the [Tokio project][tokio-security]. This includes private reporting via security@tokio.rs.\n\n[tokio-security]: https://github.com/tokio-rs/tokio/security/policy\n"
  },
  {
    "path": "codegen/Cargo.toml",
    "content": "[package]\nname = \"codegen\"\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nlicense = \"MIT\"\nedition = \"2024\"\nrust-version = { workspace = true }\n\n[dependencies]\nprotox = \"0.9\"\nprettyplease = \"0.2\"\nquote = \"1\"\nsyn = \"2\"\ntempfile = \"3.8.0\"\ntonic-prost-build = {path = \"../tonic-prost-build\", default-features = false, features = [\"cleanup-markdown\"]}\n"
  },
  {
    "path": "codegen/src/main.rs",
    "content": "use std::{\n    fs::File,\n    io::{BufWriter, Write as _},\n    path::{Path, PathBuf},\n    time::Instant,\n};\n\nuse protox::prost::Message as _;\nuse quote::quote;\nuse tonic_prost_build::FileDescriptorSet;\n\nfn main() {\n    println!(\"Running codegen...\");\n\n    let start = Instant::now();\n\n    // tonic-health\n    codegen(\n        &PathBuf::from(std::env!(\"CARGO_MANIFEST_DIR\"))\n            .parent()\n            .unwrap()\n            .join(\"tonic-health\"),\n        &[\"proto/health.proto\"],\n        &[\"proto\"],\n        &PathBuf::from(\"src/generated\"),\n        &PathBuf::from(\"src/generated/grpc_health_v1_fds.rs\"),\n        true,\n        true,\n    );\n\n    // tonic-reflection\n    codegen(\n        &PathBuf::from(std::env!(\"CARGO_MANIFEST_DIR\"))\n            .parent()\n            .unwrap()\n            .join(\"tonic-reflection\"),\n        &[\"proto/reflection_v1.proto\"],\n        &[\"proto\"],\n        &PathBuf::from(\"src/generated\"),\n        &PathBuf::from(\"src/generated/reflection_v1_fds.rs\"),\n        true,\n        true,\n    );\n    codegen(\n        &PathBuf::from(std::env!(\"CARGO_MANIFEST_DIR\"))\n            .parent()\n            .unwrap()\n            .join(\"tonic-reflection\"),\n        &[\"proto/reflection_v1alpha.proto\"],\n        &[\"proto\"],\n        &PathBuf::from(\"src/generated\"),\n        &PathBuf::from(\"src/generated/reflection_v1alpha1_fds.rs\"),\n        true,\n        true,\n    );\n\n    // tonic-types\n    codegen(\n        &PathBuf::from(std::env!(\"CARGO_MANIFEST_DIR\"))\n            .parent()\n            .unwrap()\n            .join(\"tonic-types\"),\n        &[\"proto/status.proto\", \"proto/error_details.proto\"],\n        &[\"proto\"],\n        &PathBuf::from(\"src/generated\"),\n        &PathBuf::from(\"src/generated/types_fds.rs\"),\n        false,\n        false,\n    );\n\n    // grpc\n    codegen(\n        &PathBuf::from(std::env!(\"CARGO_MANIFEST_DIR\"))\n            .parent()\n            .unwrap()\n            .join(\"grpc\"),\n        &[\"proto/echo/echo.proto\"],\n        &[\"proto\"],\n        &PathBuf::from(\"src/generated\"),\n        &PathBuf::from(\"src/generated/echo_fds.rs\"),\n        true,\n        true,\n    );\n    println!(\"Codgen completed: {}ms\", start.elapsed().as_millis());\n}\n\nfn codegen(\n    root_dir: &Path,\n    iface_files: &[&str],\n    include_dirs: &[&str],\n    out_dir: &Path,\n    file_descriptor_set_path: &Path,\n    build_client: bool,\n    build_server: bool,\n) {\n    let tempdir = tempfile::Builder::new()\n        .prefix(\"tonic-codegen-\")\n        .tempdir()\n        .unwrap();\n\n    let iface_files = iface_files.iter().map(|&path| root_dir.join(path));\n    let include_dirs = include_dirs.iter().map(|&path| root_dir.join(path));\n    let out_dir = root_dir.join(out_dir);\n    let file_descriptor_set_path = root_dir.join(file_descriptor_set_path);\n\n    let fds = protox::compile(iface_files, include_dirs).unwrap();\n\n    write_fds(&fds, &file_descriptor_set_path);\n\n    tonic_prost_build::configure()\n        .build_client(build_client)\n        .build_server(build_server)\n        .build_transport(false)\n        .out_dir(&tempdir)\n        .compile_fds(fds)\n        .unwrap();\n\n    for path in std::fs::read_dir(tempdir.path()).unwrap() {\n        let path = path.unwrap().path();\n        let to = out_dir.join(\n            path.file_name()\n                .unwrap()\n                .to_str()\n                .unwrap()\n                .strip_suffix(\".rs\")\n                .unwrap()\n                .replace('.', \"_\")\n                + \".rs\",\n        );\n        std::fs::copy(&path, &to).unwrap();\n    }\n}\n\nfn write_fds(fds: &FileDescriptorSet, path: &Path) {\n    const GENERATED_COMMENT: &str = \"// This file is @generated by codegen.\";\n\n    let mut file_header = String::new();\n\n    let mut fds = fds.clone();\n\n    for fd in fds.file.iter() {\n        let Some(source_code_info) = &fd.source_code_info else {\n            continue;\n        };\n\n        for location in &source_code_info.location {\n            for comment in &location.leading_detached_comments {\n                file_header += comment;\n            }\n        }\n    }\n\n    for fd in fds.file.iter_mut() {\n        fd.source_code_info = None;\n    }\n\n    let fds_raw = fds.encode_to_vec();\n    let tokens = quote! {\n        /// Byte encoded FILE_DESCRIPTOR_SET.\n        pub const FILE_DESCRIPTOR_SET: &[u8] = &[#(#fds_raw),*];\n    };\n    let ast = syn::parse2(tokens).unwrap();\n    let formatted = prettyplease::unparse(&ast);\n\n    let mut writer = BufWriter::new(File::create(path).unwrap());\n\n    writer.write_all(GENERATED_COMMENT.as_bytes()).unwrap();\n    writer.write_all(b\"\\n\").unwrap();\n\n    if !file_header.is_empty() {\n        let file_header = comment_out(&file_header);\n        writer.write_all(file_header.as_bytes()).unwrap();\n        writer.write_all(b\"\\n\").unwrap();\n    }\n\n    writer.write_all(formatted.as_bytes()).unwrap()\n}\n\nfn comment_out(s: &str) -> String {\n    s.split('\\n')\n        .map(|line| format!(\"// {line}\"))\n        .collect::<Vec<String>>()\n        .join(\"\\n\")\n}\n"
  },
  {
    "path": "examples/Cargo.toml",
    "content": "[package]\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2024\"\nlicense = \"MIT\"\nname = \"examples\"\n\n[[bin]]\nname = \"helloworld-server\"\npath = \"src/helloworld/server.rs\"\n\n[[bin]]\nname = \"helloworld-client\"\npath = \"src/helloworld/client.rs\"\n\n[[bin]]\nname = \"blocking-server\"\npath = \"src/blocking/server.rs\"\n\n[[bin]]\nname = \"blocking-client\"\npath = \"src/blocking/client.rs\"\n\n[[bin]]\nname = \"routeguide-server\"\npath = \"src/routeguide/server.rs\"\nrequired-features = [\"routeguide\"]\n\n[[bin]]\nname = \"routeguide-client\"\npath = \"src/routeguide/client.rs\"\nrequired-features = [\"routeguide\"]\n\n[[bin]]\nname = \"authentication-client\"\npath = \"src/authentication/client.rs\"\n\n[[bin]]\nname = \"authentication-server\"\npath = \"src/authentication/server.rs\"\n\n[[bin]]\nname = \"load-balance-client\"\npath = \"src/load_balance/client.rs\"\n\n[[bin]]\nname = \"load-balance-server\"\npath = \"src/load_balance/server.rs\"\n\n[[bin]]\nname = \"dynamic-load-balance-client\"\npath = \"src/dynamic_load_balance/client.rs\"\n\n[[bin]]\nname = \"dynamic-load-balance-server\"\npath = \"src/dynamic_load_balance/server.rs\"\n\n[[bin]]\nname = \"tls-client\"\npath = \"src/tls/client.rs\"\nrequired-features = [\"tls\"]\n\n[[bin]]\nname = \"tls-server\"\npath = \"src/tls/server.rs\"\nrequired-features = [\"tls\"]\n\n[[bin]]\nname = \"tls-rustls-client\"\npath = \"src/tls_rustls/client.rs\"\nrequired-features = [\"tls-rustls\"]\n\n[[bin]]\nname = \"tls-rustls-server\"\npath = \"src/tls_rustls/server.rs\"\nrequired-features = [\"tls-rustls\"]\n\n[[bin]]\nname = \"tls-client-auth-server\"\npath = \"src/tls_client_auth/server.rs\"\nrequired-features = [\"tls-client-auth\"]\n\n[[bin]]\nname = \"tls-client-auth-client\"\npath = \"src/tls_client_auth/client.rs\"\nrequired-features = [\"tls-client-auth\"]\n\n[[bin]]\nname = \"tower-server\"\npath = \"src/tower/server.rs\"\nrequired-features = [\"tower\"]\n\n[[bin]]\nname = \"tower-client\"\npath = \"src/tower/client.rs\"\nrequired-features = [\"tower\"]\n\n[[bin]]\nname = \"multiplex-server\"\npath = \"src/multiplex/server.rs\"\n\n[[bin]]\nname = \"multiplex-client\"\npath = \"src/multiplex/client.rs\"\n\n[[bin]]\nname = \"gcp-client\"\npath = \"src/gcp/client.rs\"\nrequired-features = [\"gcp\"]\n\n[[bin]]\nname = \"tracing-client\"\npath = \"src/tracing/client.rs\"\nrequired-features = [\"tracing\"]\n\n[[bin]]\nname = \"tracing-server\"\npath = \"src/tracing/server.rs\"\nrequired-features = [\"tracing\"]\n\n[[bin]]\nname = \"uds-client-standard\"\npath = \"src/uds/client_standard.rs\"\nrequired-features = [\"uds\"]\n\n[[bin]]\nname = \"uds-client-with-connector\"\npath = \"src/uds/client_with_connector.rs\"\nrequired-features = [\"uds\"]\n\n[[bin]]\nname = \"uds-server\"\npath = \"src/uds/server.rs\"\nrequired-features = [\"uds\"]\n\n[[bin]]\nname = \"interceptor-client\"\npath = \"src/interceptor/client.rs\"\n\n[[bin]]\nname = \"interceptor-server\"\npath = \"src/interceptor/server.rs\"\n\n[[bin]]\nname = \"health-server\"\npath = \"src/health/server.rs\"\nrequired-features = [\"health\"]\n\n[[bin]]\nname = \"reflection-server\"\npath = \"src/reflection/server.rs\"\nrequired-features = [\"reflection\"]\n\n[[bin]]\nname = \"autoreload-server\"\npath = \"src/autoreload/server.rs\"\nrequired-features = [\"autoreload\"]\n\n[[bin]]\nname = \"compression-server\"\npath = \"src/compression/server.rs\"\nrequired-features = [\"compression\"]\n\n[[bin]]\nname = \"compression-client\"\npath = \"src/compression/client.rs\"\nrequired-features = [\"compression\"]\n\n[[bin]]\nname = \"mock\"\npath = \"src/mock/mock.rs\"\nrequired-features = [\"mock\"]\n\n[[bin]]\nname = \"grpc-web-server\"\npath = \"src/grpc-web/server.rs\"\nrequired-features = [\"grpc-web\"]\n\n[[bin]]\nname = \"grpc-web-client\"\npath = \"src/grpc-web/client.rs\"\nrequired-features = [\"grpc-web\"]\n\n[[bin]]\nname = \"streaming-client\"\npath = \"src/streaming/client.rs\"\nrequired-features = [\"streaming\"]\n\n[[bin]]\nname = \"streaming-server\"\npath = \"src/streaming/server.rs\"\nrequired-features = [\"streaming\"]\n\n[[bin]]\nname = \"json-codec-client\"\npath = \"src/json-codec/client.rs\"\nrequired-features = [\"json-codec\"]\n\n[[bin]]\nname = \"json-codec-server\"\npath = \"src/json-codec/server.rs\"\nrequired-features = [\"json-codec\"]\n\n[[bin]]\nname = \"richer-error-client\"\npath = \"src/richer-error/client.rs\"\nrequired-features = [\"types\"]\n\n[[bin]]\nname = \"richer-error-server\"\npath = \"src/richer-error/server.rs\"\nrequired-features = [\"types\"]\n\n[[bin]]\nname = \"richer-error-client-vec\"\npath = \"src/richer-error/client_vec.rs\"\nrequired-features = [\"types\"]\n\n[[bin]]\nname = \"richer-error-server-vec\"\npath = \"src/richer-error/server_vec.rs\"\nrequired-features = [\"types\"]\n\n[[bin]]\nname = \"dynamic-server\"\npath = \"src/dynamic/server.rs\"\n\n[[bin]]\nname = \"h2c-server\"\npath = \"src/h2c/server.rs\"\nrequired-features = [\"h2c\"]\n\n[[bin]]\nname = \"h2c-client\"\npath = \"src/h2c/client.rs\"\nrequired-features = [\"h2c\"]\n\n[[bin]]\nname = \"cancellation-server\"\npath = \"src/cancellation/server.rs\"\nrequired-features = [\"cancellation\"]\n\n[[bin]]\nname = \"cancellation-client\"\npath = \"src/cancellation/client.rs\"\n\n[[bin]]\nname = \"codec-buffers-server\"\npath = \"src/codec_buffers/server.rs\"\n\n[[bin]]\nname = \"codec-buffers-client\"\npath = \"src/codec_buffers/client.rs\"\n\n\n[features]\ngcp = [\"dep:prost-types\", \"tonic/tls-ring\"]\nrouteguide = [\"dep:async-stream\", \"dep:tokio-stream\", \"dep:rand\", \"dep:serde\", \"dep:serde_json\"]\nreflection = [\"dep:tonic-reflection\"]\nautoreload = [\"dep:tokio-stream\", \"tokio-stream?/net\", \"dep:listenfd\"]\nhealth = [\"dep:tonic-health\"]\ngrpc-web = [\"dep:tonic-web\", \"dep:bytes\", \"dep:http\", \"dep:hyper\", \"dep:hyper-util\", \"dep:tracing-subscriber\", \"dep:tower\", \"dep:tower-http\", \"tower-http?/cors\"]\ntracing = [\"dep:tracing\", \"dep:tracing-subscriber\"]\nuds = [\"dep:tokio-stream\", \"tokio-stream?/net\", \"dep:tower\", \"dep:hyper\", \"dep:hyper-util\"]\nstreaming = [\"dep:tokio-stream\", \"dep:h2\"]\nmock = [\"dep:tokio-stream\", \"dep:tower\", \"dep:hyper-util\"]\njson-codec = [\"dep:serde\", \"dep:serde_json\", \"dep:bytes\"]\ncompression = [\"tonic/gzip\"]\ntls = [\"tonic/tls-ring\"]\ntls-rustls = [\"dep:http\", \"dep:hyper\", \"dep:hyper-util\", \"dep:hyper-rustls\", \"dep:tower\", \"tower-http/util\", \"tower-http/add-extension\", \"dep:tokio-rustls\"]\ntls-client-auth = [\"tonic/tls-ring\"]\ntypes = [\"dep:tonic-types\"]\nh2c = [\"dep:hyper\", \"dep:tower\", \"dep:http\", \"dep:hyper-util\"]\ncancellation = [\"dep:tokio-util\"]\n\nfull = [\"gcp\", \"routeguide\", \"reflection\", \"autoreload\", \"health\", \"grpc-web\", \"tracing\", \"uds\", \"streaming\", \"mock\", \"json-codec\", \"compression\", \"tls\", \"tls-rustls\", \"tls-client-auth\", \"types\", \"cancellation\", \"h2c\"]\ntower = [\"dep:tower\", \"dep:http\"]\ndefault = [\"full\"]\n\n[dependencies]\n# Common dependencies\ntokio = { version = \"1.0\", features = [\"rt-multi-thread\", \"macros\"] }\nprost = \"0.14\"\ntonic = { path = \"../tonic\" }\ntonic-prost = { path = \"../tonic-prost\" }\n# Optional dependencies\ntonic-web = { path = \"../tonic-web\", optional = true }\ntonic-health = { path = \"../tonic-health\", optional = true }\ntonic-reflection = { path = \"../tonic-reflection\", optional = true }\ntonic-types = { path = \"../tonic-types\", optional = true }\nasync-stream = { version = \"0.3\", optional = true }\ntokio-stream = { version = \"0.1\", optional = true }\ntokio-util = { version = \"0.7.8\", optional = true }\ntower = { version = \"0.5\", optional = true }\nrand = { version = \"0.9\", optional = true }\nserde = { version = \"1.0\", features = [\"derive\"], optional = true }\nserde_json = { version = \"1.0\", optional = true }\ntracing = { version = \"0.1.16\", optional = true }\ntracing-subscriber = { version = \"0.3\", features = [\"tracing-log\", \"fmt\"], optional = true }\nprost-types = { version = \"0.14\", optional = true }\nhttp = { version = \"1\", optional = true }\nhyper = { version = \"1\", optional = true }\nhyper-util = { version = \"0.1.4\", optional = true }\nlistenfd = { version = \"1.0\", optional = true }\nbytes = { version = \"1\", optional = true }\nh2 = { version = \"0.4\", optional = true }\ntokio-rustls = { version = \"0.26.1\", optional = true, features = [\"ring\", \"tls12\"], default-features = false }\nhyper-rustls = { version = \"0.27.0\", features = [\"http2\", \"ring\", \"tls12\"], optional = true, default-features = false }\ntower-http = { version = \"0.6\", optional = true }\n\n[build-dependencies]\ntonic-prost-build = { path = \"../tonic-prost-build\" }\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples\n\nSet of examples that show off the features provided by `tonic`.\n\nIn order to build these examples, you must have the `protoc` Protocol Buffers compiler\ninstalled, along with the Protocol Buffers resource files.\n\nUbuntu:\n\n```bash\nsudo apt update && sudo apt upgrade -y\nsudo apt install -y protobuf-compiler libprotobuf-dev\n```\n\nAlpine Linux:\n\n```sh\nsudo apk add protoc protobuf-dev\n```\n\nmacOS:\n\nAssuming [Homebrew](https://brew.sh/) is already installed. (If not, see instructions for installing Homebrew on [the Homebrew website](https://brew.sh/).)\n\n```zsh\nbrew install protobuf\n```\n\n## Helloworld\n\n### Client\n\n```bash\n$ cargo run --bin helloworld-client\n```\n\n### Server\n\n```bash\n$ cargo run --bin helloworld-server\n```\n\n## RouteGuide\n\n### Client\n\n```bash\n$ cargo run --bin routeguide-client\n```\n\n### Server\n\n```bash\n$ cargo run --bin routeguide-server\n```\n\n## Authentication\n\n### Client\n\n```bash\n$ cargo run --bin authentication-client\n```\n\n### Server\n\n```bash\n$ cargo run --bin authentication-server\n```\n\n## Load Balance\n\n### Client\n\n```bash\n$ cargo run --bin load-balance-client\n```\n\n### Server\n\n```bash\n$ cargo run --bin load-balance-server\n```\n\n## Dynamic Load Balance\n\n### Client\n\n```bash\n$ cargo run --bin dynamic-load-balance-client\n```\n\n### Server\n\n```bash\n$ cargo run --bin dynamic-load-balance-server\n```\n\n## TLS (rustls)\n\n### Client\n\n```bash\n$ cargo run --bin tls-client\n```\n\n### Server\n\n```bash\n$ cargo run --bin tls-server\n```\n\n## Health Checking\n\n### Server\n\n```bash\n$ cargo run --bin health-server\n```\n\n## Server Reflection\n\n### Server\n```bash\n$ cargo run --bin reflection-server\n```\n\n## Tower Middleware\n\n### Server\n\n```bash\n$ cargo run --bin tower-server\n```\n\n## Autoreloading Server\n\n### Server\n```bash\nsystemfd --no-pid -s http::[::1]:50051 -- cargo watch -x 'run --bin autoreload-server'\n```\n\n### Notes:\n\nIf you are using the `codegen` feature, then the following dependencies are\n**required**:\n\n* [bytes](https://crates.io/crates/bytes)\n* [prost](https://crates.io/crates/prost)\n* [prost-derive](https://crates.io/crates/prost-derive)\n\nThe autoload example requires the following crates installed globally:\n\n* [systemfd](https://crates.io/crates/systemfd)\n* [cargo-watch](https://crates.io/crates/cargo-watch)\n\n## Richer Error\n\nBoth clients and both servers do the same thing, but using the two different\napproaches. Run one of the servers in one terminal, and then run the clients\nin another.\n\n### Client using the `ErrorDetails` struct\n\n```bash\n$ cargo run --bin richer-error-client\n```\n\n### Client using a vector of error message types\n\n```bash\n$ cargo run --bin richer-error-client-vec\n```\n\n### Server using the `ErrorDetails` struct\n\n```bash\n$ cargo run --bin richer-error-server\n```\n\n### Server using a vector of error message types\n\n```bash\n$ cargo run --bin richer-error-server-vec\n```\n"
  },
  {
    "path": "examples/build.rs",
    "content": "use std::{env, path::PathBuf};\n\nfn main() {\n    tonic_prost_build::configure()\n        .compile_protos(&[\"proto/routeguide/route_guide.proto\"], &[\"proto\"])\n        .unwrap();\n\n    let out_dir = PathBuf::from(env::var(\"OUT_DIR\").unwrap());\n    tonic_prost_build::configure()\n        .file_descriptor_set_path(out_dir.join(\"helloworld_descriptor.bin\"))\n        .compile_protos(&[\"proto/helloworld/helloworld.proto\"], &[\"proto\"])\n        .unwrap();\n\n    tonic_prost_build::compile_protos(\"proto/echo/echo.proto\").unwrap();\n\n    tonic_prost_build::compile_protos(\"proto/unaryecho/echo.proto\").unwrap();\n\n    tonic_prost_build::configure()\n        .server_mod_attribute(\"attrs\", \"#[cfg(feature = \\\"server\\\")]\")\n        .server_attribute(\"Echo\", \"#[derive(PartialEq)]\")\n        .client_mod_attribute(\"attrs\", \"#[cfg(feature = \\\"client\\\")]\")\n        .client_attribute(\"Echo\", \"#[derive(PartialEq)]\")\n        .compile_protos(&[\"proto/attrs/attrs.proto\"], &[\"proto\"])\n        .unwrap();\n\n    tonic_prost_build::configure()\n        .build_server(false)\n        .compile_protos(\n            &[\"proto/googleapis/google/pubsub/v1/pubsub.proto\"],\n            &[\"proto/googleapis\"],\n        )\n        .unwrap();\n\n    build_json_codec_service();\n\n    let smallbuff_copy = out_dir.join(\"smallbuf\");\n    let _ = std::fs::create_dir(smallbuff_copy.clone()); // This will panic below if the directory failed to create\n    tonic_prost_build::configure()\n        .out_dir(smallbuff_copy)\n        .codec_path(\"crate::common::SmallBufferCodec\")\n        .compile_protos(&[\"proto/helloworld/helloworld.proto\"], &[\"proto\"])\n        .unwrap();\n}\n\n// Manually define the json.helloworld.Greeter service which used a custom JsonCodec to use json\n// serialization instead of protobuf for sending messages on the wire.\n// This will result in generated client and server code which relies on its request, response and\n// codec types being defined in a module `crate::common`.\n//\n// See the client/server examples defined in `src/json-codec` for more information.\nfn build_json_codec_service() {\n    let greeter_service = tonic_prost_build::manual::Service::builder()\n        .name(\"Greeter\")\n        .package(\"json.helloworld\")\n        .method(\n            tonic_prost_build::manual::Method::builder()\n                .name(\"say_hello\")\n                .route_name(\"SayHello\")\n                .input_type(\"crate::common::HelloRequest\")\n                .output_type(\"crate::common::HelloResponse\")\n                .codec_path(\"crate::common::JsonCodec\")\n                .build(),\n        )\n        .build();\n\n    tonic_prost_build::manual::Builder::new().compile(&[greeter_service]);\n}\n"
  },
  {
    "path": "examples/data/gcp/roots.pem",
    "content": "# Operating CA: Comodo Group\n# Issuer: CN=AAA Certificate Services O=Comodo CA Limited\n# Subject: CN=AAA Certificate Services O=Comodo CA Limited\n# Label: \"Comodo AAA Services root\"\n# Serial: 1\n# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0\n# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49\n# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4\n-----BEGIN CERTIFICATE-----\nMIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\nMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\nGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\nYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\nMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\nBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\nGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\nBtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\nYgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\nrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\nez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\noBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\nMAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\nQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\nb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\nAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\nGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\nRt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\nG9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\nl2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\nsmPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n-----END CERTIFICATE-----\n\n# Operating CA: Comodo Group\n# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network\n# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network\n# Label: \"AddTrust External Root\"\n# Serial: 1\n# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f\n# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68\n# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2\n-----BEGIN CERTIFICATE-----\nMIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU\nMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs\nIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290\nMB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux\nFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h\nbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v\ndDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt\nH7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9\nuMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX\nmk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX\na0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN\nE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0\nWicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD\nVR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0\nJvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\ncnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx\nIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN\nAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH\nYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5\n6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC\nNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX\nc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a\nmnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=\n-----END CERTIFICATE-----\n\n# Operating CA: Comodo Group\n# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited\n# Subject: CN=COMODO Certification Authority O=COMODO CA Limited\n# Label: \"COMODO Certification Authority\"\n# Serial: 104350513648249232941998508985834464573\n# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75\n# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b\n# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66\n-----BEGIN CERTIFICATE-----\nMIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB\ngTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV\nBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw\nMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl\nYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P\nRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0\naG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3\nUcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI\n2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8\nQ5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp\n+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+\nDT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O\nnKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW\n/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g\nPKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u\nQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY\nSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv\nIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/\nRxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4\nzJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd\nBA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB\nZQ==\n-----END CERTIFICATE-----\n\n# Operating CA: Comodo Group\n# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited\n# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited\n# Label: \"COMODO ECC Certification Authority\"\n# Serial: 41578283867086692638256921589707938090\n# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23\n# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11\n# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7\n-----BEGIN CERTIFICATE-----\nMIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL\nMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\nBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT\nIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw\nMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy\nZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N\nT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR\nFtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J\ncfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW\nBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\nBAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm\nfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv\nGDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n-----END CERTIFICATE-----\n\n# Operating CA: Comodo Group\n# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited\n# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited\n# Label: \"COMODO RSA Certification Authority\"\n# Serial: 101909084537582093308941363524873193117\n# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18\n# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4\n# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34\n-----BEGIN CERTIFICATE-----\nMIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB\nhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\nA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV\nBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5\nMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT\nEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\nQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR\n6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X\npz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC\n9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV\n/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf\nZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z\n+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w\nqP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah\nSL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC\nu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf\nFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq\ncrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\nFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB\n/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl\nwFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM\n4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV\n2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna\nFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ\nCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK\nboHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke\njkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL\nS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb\nQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl\n0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB\nNVOFBkpdn627G190\n-----END CERTIFICATE-----\n\n# Operating CA: Comodo Group\n# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network\n# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network\n# Label: \"USERTrust ECC Certification Authority\"\n# Serial: 123013823720199481456569720443997572134\n# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1\n# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0\n# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a\n-----BEGIN CERTIFICATE-----\nMIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\neSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\nJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\nMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\nCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\nVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\naWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\nI+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\no4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\nA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\nVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\nzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\nRNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n-----END CERTIFICATE-----\n\n# Operating CA: Comodo Group\n# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network\n# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network\n# Label: \"USERTrust RSA Certification Authority\"\n# Serial: 2645093764781058787591871645665788717\n# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5\n# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e\n# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2\n-----BEGIN CERTIFICATE-----\nMIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB\niDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\ncnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\nBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw\nMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\nBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\naGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy\ndGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\nAoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B\n3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY\ntJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/\nFp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2\nVN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT\n79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6\nc0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT\nYo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l\nc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee\nUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE\nHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\nBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G\nA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF\nUp/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO\nVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3\nATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs\n8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR\niQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze\nSf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ\nXHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/\nqS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB\nVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB\nL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG\njjxDah2nGN59PRbxYvnKkKj9\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust\n# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust\n# Label: \"Baltimore CyberTrust Root\"\n# Serial: 33554617\n# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4\n# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74\n# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb\n-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\nRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\nVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\nDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\nZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\nVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\nmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\nIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\nmpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\nXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\ndc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\njl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\nBE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\nDQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\njkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\nEpn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\nksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\nR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc\n# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc\n# Label: \"Cybertrust Global Root\"\n# Serial: 4835703278459682877484360\n# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1\n# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6\n# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3\n-----BEGIN CERTIFICATE-----\nMIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG\nA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh\nbCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE\nChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS\nb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5\n7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS\nJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y\nHLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP\nt3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz\nFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY\nXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\nMB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw\nhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js\nMB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA\nA4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj\nWqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx\nXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o\nomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc\nA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW\nWL1WMRJOEcgh4LMRkWXbtKaIOM5V\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert Assured ID Root CA\"\n# Serial: 17154717934120587862167794914071425081\n# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72\n# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43\n# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c\n-----BEGIN CERTIFICATE-----\nMIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv\nb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl\ncnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c\nJpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP\nmDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+\nwRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4\nVYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/\nAUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB\nAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW\nBBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun\npyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC\ndWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf\nfwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm\nNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx\nH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\n+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert Assured ID Root G2\"\n# Serial: 15385348160840213938643033620894905419\n# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d\n# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f\n# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85\n-----BEGIN CERTIFICATE-----\nMIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv\nb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl\ncnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA\nn61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc\nbiJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp\nEgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA\nbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu\nYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB\nAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW\nBBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI\nQW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I\n0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni\nlmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9\nB5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv\nON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo\nIhNzbM8m9Yop5w==\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert Assured ID Root G3\"\n# Serial: 15459312981008553731928384953135426796\n# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb\n# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89\n# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2\n-----BEGIN CERTIFICATE-----\nMIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw\nCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\nZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg\nRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV\nUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\nY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq\nhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf\nZn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q\nRSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\nBAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD\nAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY\nJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv\n6pZjamVFkpUBtA==\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert Global Root CA\"\n# Serial: 10944719598952040374951832963794454346\n# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e\n# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36\n# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61\n-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\nQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\nMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\nb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\nCSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\nnh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\nT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\ngdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\nBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\nTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\nDQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\nhMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\nPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\nYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\nCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert Global Root G2\"\n# Serial: 4293743540046975378534879503202253541\n# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44\n# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4\n# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f\n-----BEGIN CERTIFICATE-----\nMIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\nMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\nb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\nq2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\ntCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\nvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\nBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\nNeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\nFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\npLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\nMrY=\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert Global Root G3\"\n# Serial: 7089244469030293291760083333884364146\n# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca\n# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e\n# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0\n-----BEGIN CERTIFICATE-----\nMIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw\nCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\nZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe\nFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw\nEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x\nIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF\nK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG\nfp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO\nZ9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd\nBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx\nAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/\noAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8\nsycX\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert High Assurance EV Root CA\"\n# Serial: 3553400076410547919724730734378100087\n# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a\n# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25\n# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf\n-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\nZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\nMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\nLmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\nRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\nPNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\nxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\nIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\nhzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\nEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\nMAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\nFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\nnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\neM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\nhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\nYzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\nvEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n+OkuE6N36B9K\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com\n# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com\n# Label: \"DigiCert Trusted Root G4\"\n# Serial: 7451500558977370777930084869016614236\n# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49\n# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4\n# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88\n-----BEGIN CERTIFICATE-----\nMIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg\nRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV\nUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\nY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG\nSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y\nithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If\nxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV\nySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO\nDCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ\njdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/\nCNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi\nEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM\nfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY\nuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK\nchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t\n9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\nhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD\nggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2\nSV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd\n+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc\nfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa\nsjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N\ncCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N\n0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie\n4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI\nr/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1\n/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm\ngKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+\n-----END CERTIFICATE-----\n\n# Operating CA: DigiCert\n# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.\n# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.\n# Label: \"GeoTrust Global CA\"\n# Serial: 144470\n# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5\n# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12\n# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a\n-----BEGIN CERTIFICATE-----\nMIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\nMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\nYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\nEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\nR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\nfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\niS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\nbw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\nMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\nephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\nuMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\nZ57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\ntQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\nPseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\nhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.\n# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.\n# Label: \"Entrust Root Certification Authority\"\n# Serial: 1164660820\n# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4\n# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9\n# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c\n-----BEGIN CERTIFICATE-----\nMIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC\nVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0\nLm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW\nKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl\ncnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw\nNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw\nNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy\nZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV\nBAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ\nKoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo\nNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4\n4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9\nKlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI\nrb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi\n94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB\nsDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi\ngA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo\nkORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE\nvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\nA4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t\nO1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua\nAGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP\n9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/\neu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m\n0vdXcDazv/wor3ElhVsT/h5/WrQ8\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only\n# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only\n# Label: \"Entrust Root Certification Authority - EC1\"\n# Serial: 51543124481930649114116133369\n# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc\n# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47\n# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5\n-----BEGIN CERTIFICATE-----\nMIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG\nA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3\nd3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu\ndHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq\nRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy\nMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD\nVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0\nL2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g\nZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD\nZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi\nA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt\nByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH\nBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O\nBBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC\nR98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX\nhTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only\n# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only\n# Label: \"Entrust Root Certification Authority - G2\"\n# Serial: 1246989352\n# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2\n# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4\n# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39\n-----BEGIN CERTIFICATE-----\nMIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC\nVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50\ncnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs\nIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz\ndCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy\nNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu\ndHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt\ndGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0\naG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj\nYXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T\nRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN\ncCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW\nwcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1\nU1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0\njaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP\nBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN\nBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/\njTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\nRkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v\n1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R\nnAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH\nVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited\n# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited\n# Label: \"Entrust.net Premium 2048 Secure Server CA\"\n# Serial: 946069240\n# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90\n# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31\n# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77\n-----BEGIN CERTIFICATE-----\nMIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML\nRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp\nbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5\nIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp\nZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3\nMjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3\nLmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp\nYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG\nA1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq\nK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe\nsYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX\nMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT\nXTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/\nHoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub\nj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo\nU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf\nzX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b\nu/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+\nbYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er\nfF6adulZkMV8gzURZVE=\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=AffirmTrust Commercial O=AffirmTrust\n# Subject: CN=AffirmTrust Commercial O=AffirmTrust\n# Label: \"AffirmTrust Commercial\"\n# Serial: 8608355977964138876\n# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7\n# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7\n# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7\n-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE\nBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz\ndCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL\nMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp\ncm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP\nHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr\nba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL\nMeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1\nyHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr\nVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/\nnx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ\nKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG\nXUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj\nvbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt\nZ8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g\nN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC\nnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=AffirmTrust Networking O=AffirmTrust\n# Subject: CN=AffirmTrust Networking O=AffirmTrust\n# Label: \"AffirmTrust Networking\"\n# Serial: 8957382827206547757\n# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f\n# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f\n# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b\n-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE\nBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz\ndCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL\nMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp\ncm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\nAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y\nYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua\nkCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL\nQESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp\n6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG\nyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i\nQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ\nKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO\ntDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu\nQY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ\nLgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u\nolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48\nx3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=AffirmTrust Premium O=AffirmTrust\n# Subject: CN=AffirmTrust Premium O=AffirmTrust\n# Label: \"AffirmTrust Premium\"\n# Serial: 7893706540734352110\n# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57\n# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27\n# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a\n-----BEGIN CERTIFICATE-----\nMIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE\nBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz\ndCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG\nA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U\ncnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf\nqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ\nJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ\n+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS\ns8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5\nHMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7\n70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG\nV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S\nqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S\n5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia\nC1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX\nOwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE\nFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\nBAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2\nKI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg\nNt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B\n8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ\nMKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc\n0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ\nu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF\nu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH\nYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8\nGKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO\nRtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e\nKeC2uAloGRwYQw==\n-----END CERTIFICATE-----\n\n# Operating CA: Entrust Datacard\n# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust\n# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust\n# Label: \"AffirmTrust Premium ECC\"\n# Serial: 8401224907861490260\n# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d\n# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb\n# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23\n-----BEGIN CERTIFICATE-----\nMIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC\nVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ\ncmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ\nBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt\nVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D\n0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9\nss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G\nA1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G\nA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs\naobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I\nflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==\n-----END CERTIFICATE-----\n\n# Operating CA: GlobalSign\n# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA\n# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA\n# Label: \"GlobalSign Root CA\"\n# Serial: 4835703278459707669005204\n# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a\n# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c\n# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99\n-----BEGIN CERTIFICATE-----\nMIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\nA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\nb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\nMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\nYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\naWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\njc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\nxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\nsnUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\nU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\nBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\nAQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\nyj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\nAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\nDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\nHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n-----END CERTIFICATE-----\n\n# Operating CA: GlobalSign\n# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3\n# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3\n# Label: \"GlobalSign Root CA - R3\"\n# Serial: 4835703278459759426209954\n# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28\n# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad\n# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b\n-----BEGIN CERTIFICATE-----\nMIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G\nA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp\nZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4\nMTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG\nA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8\nRgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT\ngHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm\nKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\nQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ\nXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw\nDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o\nLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU\nRUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp\njjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK\n6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX\nmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs\nMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\nWD9f\n-----END CERTIFICATE-----\n\n# Operating CA: GlobalSign\n# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5\n# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5\n# Label: \"GlobalSign ECC Root CA - R5\"\n# Serial: 32785792099990507226680698011560947931244\n# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08\n# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa\n# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24\n-----BEGIN CERTIFICATE-----\nMIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk\nMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH\nbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\nDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\nQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc\n8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke\nhOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD\nVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI\nKoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg\n515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO\nxwy8p2Fp8fc74SrL+SvzZpA3\n-----END CERTIFICATE-----\n\n# Operating CA: GlobalSign\n# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6\n# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6\n# Label: \"GlobalSign Root CA - R6\"\n# Serial: 1417766617973444989252670301619537\n# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae\n# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1\n# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69\n-----BEGIN CERTIFICATE-----\nMIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg\nMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh\nbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx\nMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET\nMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI\nxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k\nZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD\naNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw\nLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw\n1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX\nk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2\nSXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h\nbguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n\nWUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY\nrZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce\nMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD\nAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu\nbAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN\nnsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt\nIxg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61\n55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj\nvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf\ncDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz\noHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp\nnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs\npA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v\nJJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R\n8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4\n5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=\n-----END CERTIFICATE-----\n\n# Note: \"GlobalSign Root CA - R7\" not added on purpose. It is P-521.\n# Note: \"GlobalSign Root CA - R8\" is not yet included in Mozilla.\n\n# Operating CA: GoDaddy\n# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.\n# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.\n# Label: \"Go Daddy Root Certificate Authority - G2\"\n# Serial: 0\n# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01\n# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b\n# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da\n-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx\nEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT\nEUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp\nZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz\nNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH\nEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE\nAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD\nE6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH\n/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy\nDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh\nGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR\ntDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA\nAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\nFDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX\nWWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu\n9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr\ngIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo\n2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\nLPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI\n4uJEvlz36hz1\n-----END CERTIFICATE-----\n\n# Operating CA: GoDaddy\n# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.\n# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.\n# Label: \"Starfield Root Certificate Authority - G2\"\n# Serial: 0\n# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96\n# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e\n# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5\n-----BEGIN CERTIFICATE-----\nMIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\nEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\nHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\nZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\nMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\nb25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\naG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\nY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\nnLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\nHOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\nHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\ndloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\nHZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\nBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\nCSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\nsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\npL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\nmMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n-----END CERTIFICATE-----\n\n# Operating CA: GoDaddy\n# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority\n# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority\n# Label: \"Starfield Class 2 CA\"\n# Serial: 0\n# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24\n# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a\n# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58\n-----BEGIN CERTIFICATE-----\nMIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\nMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\nU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\nNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\nChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\nZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\nDQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\nX9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\nK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\nA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\nzt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\nYXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\nbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\nDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\nL7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\neruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\nxy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\nVSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\nWQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n-----END CERTIFICATE-----\n\n# Operating CA: GoDaddy\n# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority\n# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority\n# Label: \"Go Daddy Class 2 CA\"\n# Serial: 0\n# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67\n# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4\n# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4\n-----BEGIN CERTIFICATE-----\nMIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh\nMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE\nYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3\nMDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo\nZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg\nMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN\nADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA\nPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w\nwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\nEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY\navx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+\nYihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE\nsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h\n/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5\nIEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj\nYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD\nggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy\nOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\nTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\nHmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER\ndEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf\nReYNnyicsbkqWletNw+vHX/bvZ8=\n-----END CERTIFICATE-----\n\n# Operating CA: Google Trust Services LLC\n# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2\n# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2\n# Label: \"GlobalSign Root CA - R2\"\n# Serial: 4835703278459682885658125\n# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30\n# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe\n# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e\n-----BEGIN CERTIFICATE-----\nMIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\nA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\nZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\nMDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\nA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\nv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\neoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\ntTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\nC9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\nzq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\nmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\nV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\nbG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\nJ0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\not+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\nAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\nTBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n-----END CERTIFICATE-----\n\n# Operating CA: Google Trust Services LLC\n# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4\n# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4\n# Label: \"GlobalSign ECC Root CA - R4\"\n# Serial: 14367148294922964480859022125800977897474\n# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e\n# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb\n# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c\n-----BEGIN CERTIFICATE-----\nMIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk\nMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH\nbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\nDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\nQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ\nFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw\nDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F\nuOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX\nkPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs\newv4n4Q=\n-----END CERTIFICATE-----\n\n# Operating CA: Google Trust Services LLC\n# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1\n# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1\n# Label: \"GTS Root R1\"\n# Serial: 6e:47:a9:c5:4b:47:0c:0d:ec:33:d0:89:b9:1c:f4:e1\n# MD5 Fingerprint: 82:1A:EF:D4:D2:4A:F2:9F:E2:3D:97:06:14:70:72:85\n# SHA1 Fingerprint: E1:C9:50:E6:EF:22:F8:4C:56:45:72:8B:92:20:60:D7:D5:A7:A3:E8\n# SHA256 Fingerprint: 2A:57:54:71:E3:13:40:BC:21:58:1C:BD:2C:F1:3E:15:84:63:20:3E:CE:94:BC:F9:D3:CC:19:6B:F0:9A:54:72\n-----BEGIN CERTIFICATE-----\nMIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH\nMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\nQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\nMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\ncnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM\nf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX\nmX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7\nzUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P\nfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc\nvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4\nZor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp\nzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO\nRc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW\nk70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+\nDVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF\nlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW\nCu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1\nd5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z\nXPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR\ngyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3\nd8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv\nJ4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg\nDdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM\n+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy\nF62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9\nSQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws\nE3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl\n-----END CERTIFICATE-----\n\n# Operating CA: Google Trust Services LLC\n# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R2\n# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R2\n# Label: \"GTS Root R2\"\n# Serial: 6e:47:a9:c6:5a:b3:e7:20:c5:30:9a:3f:68:52:f2:6f\n# MD5 Fingerprint: 44:ED:9A:0E:A4:09:3B:00:F2:AE:4C:A3:C6:61:B0:8B\n# SHA1 Fingerprint: D2:73:96:2A:2A:5E:39:9F:73:3F:E1:C7:1E:64:3F:03:38:34:FC:4D\n# SHA256 Fingerprint: C4:5D:7B:B0:8E:6D:67:E6:2E:42:35:11:0B:56:4E:5F:78:FD:92:EF:05:8C:84:0A:EA:4E:64:55:D7:58:5C:60\n-----BEGIN CERTIFICATE-----\nMIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH\nMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\nQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\nMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\ncnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv\nCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg\nGjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu\nXvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd\nre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu\nPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1\nmKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K\n8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj\nx5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR\nnTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0\nkzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok\ntwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp\n8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT\nvhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT\nz9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA\npJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb\npxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB\nR64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R\nRaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk\n0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC\n5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF\nizoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn\nyOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC\n-----END CERTIFICATE-----\n\n# Operating CA: Google Trust Services LLC\n# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R3\n# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R3\n# Label: \"GTS Root R3\"\n# Serial: 6e:47:a9:c7:6c:a9:73:24:40:89:0f:03:55:dd:8d:1d\n# MD5 Fingerprint: 1A:79:5B:6B:04:52:9C:5D:C7:74:33:1B:25:9A:F9:25\n# SHA1 Fingerprint: 30:D4:24:6F:07:FF:DB:91:89:8A:0B:E9:49:66:11:EB:8C:5E:46:E5\n# SHA256 Fingerprint: 15:D5:B8:77:46:19:EA:7D:54:CE:1C:A6:D0:B0:C4:03:E0:37:A9:17:F1:31:E8:A0:4E:1E:6B:7A:71:BA:BC:E5\n-----BEGIN CERTIFICATE-----\nMIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw\nCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\nMBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\nMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\nY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout\n736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A\nDDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\nDgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk\nfCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA\nnjWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd\n-----END CERTIFICATE-----\n\n# Operating CA: Google Trust Services LLC\n# Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4\n# Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R4\n# Label: \"GTS Root R4\"\n# Serial: 6e:47:a9:c8:8b:94:b6:e8:bb:3b:2a:d8:a2:b2:c1:99\n# MD5 Fingerprint: 5D:B6:6A:C4:60:17:24:6A:1A:99:A8:4B:EE:5E:B4:26\n# SHA1 Fingerprint: 2A:1D:60:27:D9:4A:B1:0A:1C:4D:91:5C:CD:33:A0:CB:3E:2D:54:CB\n# SHA256 Fingerprint: 71:CC:A5:39:1F:9E:79:4B:04:80:25:30:B3:63:E1:21:DA:8A:30:43:BB:26:66:2F:EA:4D:CA:7F:C9:51:A4:BD\n-----BEGIN CERTIFICATE-----\nMIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw\nCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\nMBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\nMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\nY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu\nhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l\nxKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\nDgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0\nCMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx\nsbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/data/route_guide_db.json",
    "content": "[\n    {\n        \"location\": {\n            \"latitude\": 407838351,\n            \"longitude\": -746143763\n        },\n        \"name\": \"Patriots Path, Mendham, NJ 07945, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 408122808,\n            \"longitude\": -743999179\n        },\n        \"name\": \"101 New Jersey 10, Whippany, NJ 07981, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 413628156,\n            \"longitude\": -749015468\n        },\n        \"name\": \"U.S. 6, Shohola, PA 18458, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 419999544,\n            \"longitude\": -740371136\n        },\n        \"name\": \"5 Conners Road, Kingston, NY 12401, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 414008389,\n            \"longitude\": -743951297\n        },\n        \"name\": \"Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 419611318,\n            \"longitude\": -746524769\n        },\n        \"name\": \"287 Flugertown Road, Livingston Manor, NY 12758, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406109563,\n            \"longitude\": -742186778\n        },\n        \"name\": \"4001 Tremley Point Road, Linden, NJ 07036, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 416802456,\n            \"longitude\": -742370183\n        },\n        \"name\": \"352 South Mountain Road, Wallkill, NY 12589, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412950425,\n            \"longitude\": -741077389\n        },\n        \"name\": \"Bailey Turn Road, Harriman, NY 10926, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412144655,\n            \"longitude\": -743949739\n        },\n        \"name\": \"193-199 Wawayanda Road, Hewitt, NJ 07421, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 415736605,\n            \"longitude\": -742847522\n        },\n        \"name\": \"406-496 Ward Avenue, Pine Bush, NY 12566, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 413843930,\n            \"longitude\": -740501726\n        },\n        \"name\": \"162 Merrill Road, Highland Mills, NY 10930, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 410873075,\n            \"longitude\": -744459023\n        },\n        \"name\": \"Clinton Road, West Milford, NJ 07480, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412346009,\n            \"longitude\": -744026814\n        },\n        \"name\": \"16 Old Brook Lane, Warwick, NY 10990, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 402948455,\n            \"longitude\": -747903913\n        },\n        \"name\": \"3 Drake Lane, Pennington, NJ 08534, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406337092,\n            \"longitude\": -740122226\n        },\n        \"name\": \"6324 8th Avenue, Brooklyn, NY 11220, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406421967,\n            \"longitude\": -747727624\n        },\n        \"name\": \"1 Merck Access Road, Whitehouse Station, NJ 08889, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 416318082,\n            \"longitude\": -749677716\n        },\n        \"name\": \"78-98 Schalck Road, Narrowsburg, NY 12764, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 415301720,\n            \"longitude\": -748416257\n        },\n        \"name\": \"282 Lakeview Drive Road, Highland Lake, NY 12743, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 402647019,\n            \"longitude\": -747071791\n        },\n        \"name\": \"330 Evelyn Avenue, Hamilton Township, NJ 08619, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412567807,\n            \"longitude\": -741058078\n        },\n        \"name\": \"New York State Reference Route 987E, Southfields, NY 10975, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 416855156,\n            \"longitude\": -744420597\n        },\n        \"name\": \"103-271 Tempaloni Road, Ellenville, NY 12428, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404663628,\n            \"longitude\": -744820157\n        },\n        \"name\": \"1300 Airport Road, North Brunswick Township, NJ 08902, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 407113723,\n            \"longitude\": -749746483\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 402133926,\n            \"longitude\": -743613249\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 400273442,\n            \"longitude\": -741220915\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 411236786,\n            \"longitude\": -744070769\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 411633782,\n            \"longitude\": -746784970\n        },\n        \"name\": \"211-225 Plains Road, Augusta, NJ 07822, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 415830701,\n            \"longitude\": -742952812\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 413447164,\n            \"longitude\": -748712898\n        },\n        \"name\": \"165 Pedersen Ridge Road, Milford, PA 18337, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 405047245,\n            \"longitude\": -749800722\n        },\n        \"name\": \"100-122 Locktown Road, Frenchtown, NJ 08825, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 418858923,\n            \"longitude\": -746156790\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 417951888,\n            \"longitude\": -748484944\n        },\n        \"name\": \"650-652 Willi Hill Road, Swan Lake, NY 12783, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 407033786,\n            \"longitude\": -743977337\n        },\n        \"name\": \"26 East 3rd Street, New Providence, NJ 07974, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 417548014,\n            \"longitude\": -740075041\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 410395868,\n            \"longitude\": -744972325\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404615353,\n            \"longitude\": -745129803\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406589790,\n            \"longitude\": -743560121\n        },\n        \"name\": \"611 Lawrence Avenue, Westfield, NJ 07090, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 414653148,\n            \"longitude\": -740477477\n        },\n        \"name\": \"18 Lannis Avenue, New Windsor, NY 12553, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 405957808,\n            \"longitude\": -743255336\n        },\n        \"name\": \"82-104 Amherst Avenue, Colonia, NJ 07067, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 411733589,\n            \"longitude\": -741648093\n        },\n        \"name\": \"170 Seven Lakes Drive, Sloatsburg, NY 10974, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412676291,\n            \"longitude\": -742606606\n        },\n        \"name\": \"1270 Lakes Road, Monroe, NY 10950, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 409224445,\n            \"longitude\": -748286738\n        },\n        \"name\": \"509-535 Alphano Road, Great Meadows, NJ 07838, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406523420,\n            \"longitude\": -742135517\n        },\n        \"name\": \"652 Garden Street, Elizabeth, NJ 07202, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 401827388,\n            \"longitude\": -740294537\n        },\n        \"name\": \"349 Sea Spray Court, Neptune City, NJ 07753, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 410564152,\n            \"longitude\": -743685054\n        },\n        \"name\": \"13-17 Stanley Street, West Milford, NJ 07480, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 408472324,\n            \"longitude\": -740726046\n        },\n        \"name\": \"47 Industrial Avenue, Teterboro, NJ 07608, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412452168,\n            \"longitude\": -740214052\n        },\n        \"name\": \"5 White Oak Lane, Stony Point, NY 10980, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 409146138,\n            \"longitude\": -746188906\n        },\n        \"name\": \"Berkshire Valley Management Area Trail, Jefferson, NJ, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404701380,\n            \"longitude\": -744781745\n        },\n        \"name\": \"1007 Jersey Avenue, New Brunswick, NJ 08901, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 409642566,\n            \"longitude\": -746017679\n        },\n        \"name\": \"6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 408031728,\n            \"longitude\": -748645385\n        },\n        \"name\": \"1358-1474 New Jersey 57, Port Murray, NJ 07865, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 413700272,\n            \"longitude\": -742135189\n        },\n        \"name\": \"367 Prospect Road, Chester, NY 10918, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404310607,\n            \"longitude\": -740282632\n        },\n        \"name\": \"10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 409319800,\n            \"longitude\": -746201391\n        },\n        \"name\": \"11 Ward Street, Mount Arlington, NJ 07856, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406685311,\n            \"longitude\": -742108603\n        },\n        \"name\": \"300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 419018117,\n            \"longitude\": -749142781\n        },\n        \"name\": \"43 Dreher Road, Roscoe, NY 12776, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412856162,\n            \"longitude\": -745148837\n        },\n        \"name\": \"Swan Street, Pine Island, NY 10969, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 416560744,\n            \"longitude\": -746721964\n        },\n        \"name\": \"66 Pleasantview Avenue, Monticello, NY 12701, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 405314270,\n            \"longitude\": -749836354\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 414219548,\n            \"longitude\": -743327440\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 415534177,\n            \"longitude\": -742900616\n        },\n        \"name\": \"565 Winding Hills Road, Montgomery, NY 12549, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406898530,\n            \"longitude\": -749127080\n        },\n        \"name\": \"231 Rocky Run Road, Glen Gardner, NJ 08826, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 407586880,\n            \"longitude\": -741670168\n        },\n        \"name\": \"100 Mount Pleasant Avenue, Newark, NJ 07104, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 400106455,\n            \"longitude\": -742870190\n        },\n        \"name\": \"517-521 Huntington Drive, Manchester Township, NJ 08759, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 400066188,\n            \"longitude\": -746793294\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 418803880,\n            \"longitude\": -744102673\n        },\n        \"name\": \"40 Mountain Road, Napanoch, NY 12458, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 414204288,\n            \"longitude\": -747895140\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 414777405,\n            \"longitude\": -740615601\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 415464475,\n            \"longitude\": -747175374\n        },\n        \"name\": \"48 North Road, Forestburgh, NY 12777, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404062378,\n            \"longitude\": -746376177\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 405688272,\n            \"longitude\": -749285130\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 400342070,\n            \"longitude\": -748788996\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 401809022,\n            \"longitude\": -744157964\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404226644,\n            \"longitude\": -740517141\n        },\n        \"name\": \"9 Thompson Avenue, Leonardo, NJ 07737, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 410322033,\n            \"longitude\": -747871659\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 407100674,\n            \"longitude\": -747742727\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 418811433,\n            \"longitude\": -741718005\n        },\n        \"name\": \"213 Bush Road, Stone Ridge, NY 12484, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 415034302,\n            \"longitude\": -743850945\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 411349992,\n            \"longitude\": -743694161\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404839914,\n            \"longitude\": -744759616\n        },\n        \"name\": \"1-17 Bergen Court, New Brunswick, NJ 08901, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 414638017,\n            \"longitude\": -745957854\n        },\n        \"name\": \"35 Oakland Valley Road, Cuddebackville, NY 12729, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412127800,\n            \"longitude\": -740173578\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 401263460,\n            \"longitude\": -747964303\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 412843391,\n            \"longitude\": -749086026\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 418512773,\n            \"longitude\": -743067823\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404318328,\n            \"longitude\": -740835638\n        },\n        \"name\": \"42-102 Main Street, Belford, NJ 07718, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 419020746,\n            \"longitude\": -741172328\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404080723,\n            \"longitude\": -746119569\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 401012643,\n            \"longitude\": -744035134\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 404306372,\n            \"longitude\": -741079661\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 403966326,\n            \"longitude\": -748519297\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 405002031,\n            \"longitude\": -748407866\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 409532885,\n            \"longitude\": -742200683\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 416851321,\n            \"longitude\": -742674555\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 406411633,\n            \"longitude\": -741722051\n        },\n        \"name\": \"3387 Richmond Terrace, Staten Island, NY 10303, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 413069058,\n            \"longitude\": -744597778\n        },\n        \"name\": \"261 Van Sickle Road, Goshen, NY 10924, USA\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 418465462,\n            \"longitude\": -746859398\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 411733222,\n            \"longitude\": -744228360\n        },\n        \"name\": \"\"\n    },\n    {\n        \"location\": {\n            \"latitude\": 410248224,\n            \"longitude\": -747127767\n        },\n        \"name\": \"3 Hasta Way, Newton, NJ 07860, USA\"\n    }\n]\n"
  },
  {
    "path": "examples/data/tls/ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC6XFF7KXhQGBXf\n0OAcPt7sg8xlsHlYzW2A9N7FzhS8sBoVzTC/A+j6n4OkF+8tTYdi0hF/Bd+x/b3k\nh4knocY12ZVzMc2wHIVkWPdxQszRK7l0tzFvQm+JKJaquw5DuIS6oWKYATCINMbw\n+YNoF57Qh+z2Buc8rQ+fiLDR4Cv2etKl0VBwlJ0nO6yiutHTOtHl3SXcFzg9tb4K\nyBMaNVru/SMvkbL6CfKDdHymLEo9nfGFMb/hkUggTS5mJL4kAcQf2nYvPGhWXn5F\nDizFiOPLFD5ajCA7vXMz4ogxDkIhGMDObP3khdOfWs22PqOXwnNCe0LzxMnzkCpF\n+1iChaYJjGZvqKTxLb8xKkTwI9sbhFFCun1FcpSQ9N3fr51oDzrPwsB4Itoe1M7S\nsm+x5nqa6PZrmt+ZsK+RTxCQ1og1/pGOnct1HGauexD51aapMn1KXuHbGeoXS5DI\nkf3nW8lrXXDAw2a6Sm/CFlzvGnna9AZ4ldwfLfl2pIpPjQ0kIUSdti3M5mvPFc+k\n3frEBlypt0sWXec2BBAviOH0skEkqXqf5paGsuXgcAgihjGUIuxViHhdFK5hQ1dN\nLzLdBGUu/wpphhEPbjvkywge1xqjndLXAd808A+XHiYFtyWMFAsJeTAYJjERfewl\nj6Ge2gLGpZVb9MV2ZTVeYsvBkqtjXwIDAQABAoICAD2kWqlH6s1nYhjhoLeHDjqi\nT8IVENZQQNfGZ0d7Zn2RLFeowuZz1yTLDYKCDjFocw87V+Exoq/fs+d682GCD6tx\nOI9dWmFV1cN+7/3tMA1CDrpt+/KGwZjXLZr0e3/n8TNAPXn07sYm2uULSy1rnrLw\nOu+YEfWOctv8nSwWn8QMFVAWv6o1ZhP7l5tN+yiIzLPhJew6W/aBfoZXboYdPuJN\nJc3OvioZjzdvGOnoPXhLHX/GmGb2pKpWjTHpFmGXmfVFUBFIxGRJJjAWQ7XlFR/v\npr5RmjnYbNotJIpBYptK8j91arejkn+jy+ZrqrYAchp75gX2wiwHtAvo2vp1VZlD\nGOYe767tIBHRYgzXJxAH5DrdndmWlaXsVuE06hy0IE0rPXspQzr6+2+G+bld9MxG\nX/SNU6NT8xW31WM08A9BXFTFUgqBeXDKhltQ9TmWrOOEtAYXNFrMc6AP17sza4h0\nzSKY8BZukDV/qjeBSU7+U2IvKFY3mtv/87QPSePaP6uV7Df3yeLVwn11f3spqhhJ\nUgiCSHo3uQprjO6rypYmXKMXM+VOWgHesF2bCJQE8La7Z7g24xgY0Oqj7EC9QNqI\nvMjFmwMZ19HSY64JXvUxgYwgsDR/+YNVTV3JR7+Vip6huUopc60ZZTCfTsZ6s66h\nN+gWhRi4CyfvPAE32hUdAoIBAQDqHdVZneJpohGG5jhLs6IkfQJ8sVbazqIJp9I/\nozC/H8UPcc0HuCQeKZYad5lE2E8wexIuQAPpB6KkzJfcUzgI+Eytra5LBx+FyTIk\nKKycX4kcaeIF/bzV5bAp6X9QtFh2O6I8ZBAzuXSvc0iKLtGTfjNmfdJ7XSFYrnwJ\n7LA4DViS3/At/fF67gE6z4z27htu30AXIW/lbU3eeDEP5XNROPKelQAP/bTnaBXE\nRJclBjCVRpMkKGBMmUbd3+wIMro66k4cMWDxLnb9zJKAivpIt8TbLFi4MeTG74sF\ns07jLDsTxrm4WAYPhn1Rmt2woErshBvDK39YLbnteZlMi/vjAoIBAQDLx7wyrOHS\nSoUYDhwiS5XY97k8uzCMsW6S0cudIhJYr2abccj4IvlxAYWSRKEhDmos3I3TVwmh\nPyaT+tL9A7b2My5HfzNz/Y3oUVd51ufVGLE4pghJJjO6Edr5Wb7JvNpCzP2H5NjV\nswM+8ONJt0jwpRRRIaRFho4mPjwGtWXuzrL3CGBiXQefFOzZsyVtUG4uCPtcQpOU\nIbInshzDfJOymgGmbEQLsdN8XTpzGGSz0j/NpxjNT1H10KkZ9+NqfZozeql9Izey\n2fqdjsbAzKCL7y9vlrjPsEMOZKjBGWvpZBwOn+mMPc71v39jLiLBZnuYHNOKoAC1\nmxJ9Do30igtVAoIBAQC4FUsrkwxzOL8FTkJXq+BDRpRNDXgYxj78zptv9FYhAc8G\nDNpFRpIHsXVYTFAUpOznVu39tdIdSial5EVINZsq2moYaidQ0UIFBSVK7zyCHFCI\nKe1R/qibm2YAHpxADf48wTkYuSlQMnPAfSo9lQCvM50g6rA01g6hV1kqyJPrDvtl\nSXXmA/X7TedjoczaYHDrpdkUFvOP93kyA1m4gRdCdz+2V7xb1oaHKf1rfO9Ham2L\nApox5RmLQT5KuYYzEAgEyTUvz9fE7F8dwtwy/JQ911mPaHg+JOUZU0MB8XKHB8FQ\nFIL1oyjozjv9jYLhHbir7liSBsKzyAiY5HMYkD03AoIBAHFwoCjJqvCJAWxxtmG1\nGBbvWJQhVJaN05Mx7RptNC9gfUs9XXYc6iVphnT1dYlUX/DXWrByvG6iHBS2xauJ\n3NlThojQm9EPLmdMmNi/tNEg7M8vRl+KP7NuayryNc5SLmKPgPecgsT74WuxZ6XK\nvXURQK0lgDAgBpPtgzbs1nDJakEwzY8UYMDDQlKycrxW0O8ZmuwyN7t3wphsg6yj\ndgkvyIlfrcWg2a1arMYTp0OfYFtYkOsCJAsmfGxzXYsTnrrXpvB9oW0UAXqiV6xO\nfXVI0mxZSEp9weaKTJMqVrNXQnM1vCqQ4dxWHVEWBs0JAvab3XtHNP3j9LffWVDv\nY/0CggEAF5+Rx6eqFwVgbxgM1nDAzym2VCP64JqryM5PpYpQ7tcxhNSzK7/6yB4K\n/pZ9C41e7j+GRTiubuopxjBLTXuHU3i0/CcYlmPQNF/Cm72EHFvuVW6LlMefL4YV\n8fRpRthE3GbFdK2g0KHWZU2i08mToMgJWOuCrFMlpoweDI2Wa2kTvp7PfxNsY371\nf95nwXKSQHdNhbqujf56WoemYMUP2UYzrAShyXXlyvLJnJOl4rtCtTZ5z2z55lM6\ncfDWFCmj9eIjJ593bEQ7mku+2ID0OnSsRNMBEicNjXvgFMPA0o8aj6eZJcBzrPQO\nt9QUZ0RmRfLe8MaKDwmFDUIWy+Dk1A==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "examples/data/tls/ca.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFijCCA3KgAwIBAgIUao+2CjQxejCTMhfk0SNhJJ9gZK4wDQYJKoZIhvcNAQEL\nBQAwKTEOMAwGA1UECgwFVG9uaWMxFzAVBgNVBAMMDnRlc3Qtc2VydmVyX2NhMB4X\nDTI1MTExNTE4MTI0OFoXDTM1MTExMzE4MTI0OFowKTEOMAwGA1UECgwFVG9uaWMx\nFzAVBgNVBAMMDnRlc3Qtc2VydmVyX2NhMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\nMIICCgKCAgEAulxReyl4UBgV39DgHD7e7IPMZbB5WM1tgPTexc4UvLAaFc0wvwPo\n+p+DpBfvLU2HYtIRfwXfsf295IeJJ6HGNdmVczHNsByFZFj3cULM0Su5dLcxb0Jv\niSiWqrsOQ7iEuqFimAEwiDTG8PmDaBee0Ifs9gbnPK0Pn4iw0eAr9nrSpdFQcJSd\nJzusorrR0zrR5d0l3Bc4PbW+CsgTGjVa7v0jL5Gy+gnyg3R8pixKPZ3xhTG/4ZFI\nIE0uZiS+JAHEH9p2LzxoVl5+RQ4sxYjjyxQ+WowgO71zM+KIMQ5CIRjAzmz95IXT\nn1rNtj6jl8JzQntC88TJ85AqRftYgoWmCYxmb6ik8S2/MSpE8CPbG4RRQrp9RXKU\nkPTd36+daA86z8LAeCLaHtTO0rJvseZ6muj2a5rfmbCvkU8QkNaINf6Rjp3LdRxm\nrnsQ+dWmqTJ9Sl7h2xnqF0uQyJH951vJa11wwMNmukpvwhZc7xp52vQGeJXcHy35\ndqSKT40NJCFEnbYtzOZrzxXPpN36xAZcqbdLFl3nNgQQL4jh9LJBJKl6n+aWhrLl\n4HAIIoYxlCLsVYh4XRSuYUNXTS8y3QRlLv8KaYYRD2475MsIHtcao53S1wHfNPAP\nlx4mBbcljBQLCXkwGCYxEX3sJY+hntoCxqWVW/TFdmU1XmLLwZKrY18CAwEAAaOB\nqTCBpjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSc0TW892b8ugXApahDGkrR\ndjIj7TBkBgNVHSMEXTBbgBSc0TW892b8ugXApahDGkrRdjIj7aEtpCswKTEOMAwG\nA1UECgwFVG9uaWMxFzAVBgNVBAMMDnRlc3Qtc2VydmVyX2NhghRqj7YKNDF6MJMy\nF+TRI2Ekn2BkrjAOBgNVHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADggIBALib\nvntll0DzlAIQWisIILM29xxohcypxDpnvvLn5RKhulW4FOiSNCzipSq7KMVj0aPY\n2oLD6WZaS3AgzOKvviAo9M63EyLRieYMWSysDAxMKYAPNTFnaT4lwGCeypzvw9Nu\nBfGV/66TBefaWgvlE854SdvLN6xQQLc64OstjburCXmM8YiNdjv+a86V1afL45Fn\nTU2r2hB3DXaqfFXp+vnrXKQRKGplabXmUnnp4HR/vUqlDZ4/0c9q5aZktWFfd8ne\n4eSNfYibsNdWnaAxVWQjaCrNS90Vehsoe+/weYQkZv7scot9tAYqfdjxl5pjWeP7\nAypJhmYeWHwtMm32EPZAiX/UhVXMkkKWs8M4ruwlKbMceSrR5YQNTLG1wXaX+DkU\n6og0VVY9H233ep+K6r7JaG+HTc3kzvfXA0XAfGxOTC9wvclQsNMn+P60ua7O5NA1\nBbzPm2HTlY/exxYSo4ot2OelUACvObbxoVtsLfp10i8p2CpkZRwfpptcJayUEJu5\nF2dNjSAYt9X0OTLjMIz1IuUVZLzdcdcSaL09RaAB1gWkmuS/Zy9WPA7t1AyTPDEz\nGYXBGIUxEPcSVzuqGq2Ba/nQYdU+GDKi8JjT2I7V2w2pbkf/sljvM7+zgZ8/Ag3T\ngpG2yPYc30FQ2n6euD2+nA6gwGP8wzT4irXk2GaL\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/data/tls/client1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC3dUytzpnqjxW6\nDh2Ci0b4fB0iA8D251L0fVLIZE99XCXHOmv4YoFUIwTzbMEiTymgXgvqvyLgM9+v\nuXRNQi45yt111BKWSd5hTjsIr+mYuTdgRcCEDtNMwmEg+3dibHqSmXcxrg54tL5c\nRLPkozS1N5/i7tBgNpbQTdAtjFPRcGPfl2Xsc2o9IX7Jd0JdZscyQXzxmbaT2rjx\ns+QTAl7J74/HffjRVVwOhIVM18VuPlqiFmhzhrKjj3/58m+Q3xvgy2snSXC9JDsB\nGqfpFXLQg11pWsQh2f7k1ercd4RhJqJHUIa+fViSt5SAN384KynAZ/MJjDyTvMwZ\n9Wn/5DTZ57p+OgxeVnsBz/oe7EUpPoIMOSjbHPK1mHOaNqOCWsqe27SI4JLoLwsT\nealMsj8ZHz5CGKY90eQ53nVNKaX9BBmo5EqeiMjdQaNu9qlOIhAfnX7EWXUUWEvg\ntwuzOIihacGf2XDGClBJwY7ogcBfrytC9btDJBQ6a/5gwK9DpRmVhOVR64vHTUYx\nNJOOAbPaVAZCYdD6zzl9nn+oc7C41KnV/IG+cPFutb9EBfV3peodbv1zvunzGbMC\nLwX3Vve4dPukle8bXOfkjafrn+eyH0QqzMN5r9tRSsOGG6z60cs7ugOQMWJijcT7\nlKTsAveZ9vBApX4xWtgVrEEckt7z2wIDAQABAoICAAnkERZDJUPizaZnob+qsqYt\noC8in1dbHBCCZowsnFHYk1DXyCpuunpGyRA2tNLyDFR7vY4ScAGWdQuMUXDjjd/K\nctYqG4vEFRvkk9o2txQSKEzQdeiow/ZHeeUaqafCIXmgkdnj1ck8NWcpbRQj7cY3\nZtoH9hlkgrey+kj6X9UoMg+ZTK11gNd65Chd0v4mJGcukLCV5k9iY3Dkj09XDrU5\nwo6xg/talslRlmjmLobFuy0x+BUCa28rYBhMXHzQX+MRad2HCsT9HGaa1qKtErDw\njtYMnAvB17Q5XvLenrco1hGc4ybcqyx90/Z1si4yZYsyD4WxlzJ/40vNp2wHFFzz\nqmgtgyFa2TiMPcsbgHyM3C8k0dYwFo74uGrjFJyRGpKKZUVNihjcG5uqLxi4ay0V\naU2Q8LyUbP6gm5TH3xy2jX3/RDJAnmk1/apmfC73NwpoQVDXFgrBu3P2r+HuECDC\njFnPUsrCtPGVWmX4+dJi+ZgUJ4DRVwI2PQYIPzp4e9SUk0n4P3OZg8lXRWXOmQEy\nVBYHcoICq9sLgxjyzBsYctqFxrLswDSX4myj8IcW+XfZVuNUoxuj5MLIS9Vc4HbM\nqLSQIlhTyhmTfKAIV7owL8X9rR/MMlpdiUDjU8kXpSmMomb0ASESCIXhvmC3AkUL\nj6R2PwSZmuCESM7OXPtBAoIBAQDyldSeFdW7yLUWjp4ovMnxWgATjTOQvOU5Hcxj\n53nrPIj8oa/ZfgrWIKMfRfKaX/s+SH/+j3Vv3UFJeCPhWWayNJAUbqEd8Kvl+K77\nea+rlr3mI+GOv/iRq3V3WGnkPXrhIuDo0ORm+eWOZOWAFPL7jA0NP2He6h3PWujA\nbrscor6ZXxMypi7yIgyBx/REHGkuJL+1aad+omF5rW3zG7xKDirTfsPQQOhf0BlT\n5obbSn0KruSL4GqiRavMBrOxU7Pjhb67JuN0QPPcrVvLcx/YvDKGCPmgbiUxspal\nRSGkJAlQ8LTgMRs6xQ6PHmhO5N/bgp4zKKWvkr62C2i3RwxvAoIBAQDBmm8SvTup\nMZITkyhfxTqXS4AxISLeLDjBuNnvXZR7yhol/pUzkA3HfkJWIXNwRYElFgBYbL8f\nEDeMU+hOx4V8oJCkbANASnBpRd4DmLcj7P7YUSVrWArKO+y8bUz0sy50WXR7Zop9\nTAilcpwrOWG6SfpewdjmstatT06ou/1AU+Ny+Owo2rChUet7DLrgQwZy+XE405v4\n1d/orM87PZ27o1/080dGPB3Ny0nrpWxJhT4J+iz82+p+vWvaTnSrmCi2l57i+dbc\nTd6C7rbiYjn8Y/jY9EJU00o/Dx4Uf0rsFsjJ+IOF7qQHJZuEWO68jR67c23am3lE\n6KO51ULkNN1VAoIBAFjF6ePcG7Y3kcVqdYh05fXTuLlu79LkvYG0XOqmd+BU69B/\nnumZjX+ku+0i3NAPldLKF0Th3NkN/+lR9NdvrvxB7gP8JCvfuhhTdD2E33uMk3vX\n36Asslskgr0k9sNWmFQxPlsUrrDcfFwqoi3H/M9/Bfu2GSvJQxVxsEFThFfLWrKn\nr0/WrtFfEnKf6MzQFNGVEy7hNjFKXR95DwZrPPFg091Hw4K/bgo6Djq83tb7IF07\neVmSy5MMqfzk6vdWqTr248B7T7toVZWJP1FplNrsrBSOzkMea7APKb/bV59IrLwZ\nCigM8GkGWfiX6RYN/bnHx/rywgdJTU8zR6PidTMCggEActpKMITAgwQcU66GUiJw\nOtcYiozM4Z68YPhnmaAbeUCROJ8KJle8RO/7LJuVnzIshjLCK7L/ws7dFUul0i59\nW0zp4hEN8LL4cwt2xQ1xAEgVe4DQQRku9YCNVc9FyxkNYwq6loZjfCeCLZyLVv0o\no9pFRLedFGdeAdy9nk4/1Eyv70IK38W06U7u8sW/i1FX3xdp+rtWmU1QEvmJyuwn\nyewG/grg6qK5T5/dD4XIcukvv72BuNRCDcQT2qOWhUG0TXYvVRnARFuRuH0jU7PQ\nEJHCS/rD6wyZzEUMpD5L1TlDDsZ2SBslhfPiiaY0ovjZFX1J21lGnQGiN5lzoGxY\nLQKCAQEAjawytF2oj8Sm8woMzHxuL+Fx2alPQy8Cn+O9CItdPA6mQCUbIh1QaXHy\nl9ECxysGMxU13TZ2mlK13jr2EfBPH1EkGkBhwiMYhcixZkQoBVR7qRUIGPdT3B/K\naYGUDQB8n/u66MXwP4xkuq3FWkN5EFbOiQHnXdK3A6RyOlnB2WPq57J3JAkM6QAj\nm144rNSrdAhVSjxtUzzDTxr4UmNsnSqhBq84OFbaoy16YHO2DRW/I5pwko0USGBo\nCq3PAcfHquktqColM9gS6sQv6dsKIE5zF0rU4ilh8nNkblc056xXMPr+jU28a9Y4\n8Y87Hf3mj7ies/4Fweb+7nY2QUVjwQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "examples/data/tls/client1.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFRDCCAyygAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwKTEOMAwGA1UECgwFVG9u\naWMxFzAVBgNVBAMMDnRlc3QtY2xpZW50X2NhMB4XDTI1MTExNTE4MTI0OVoXDTM1\nMTExMzE4MTI0OVowJzEOMAwGA1UECgwFVG9uaWMxFTATBgNVBAMMDHRlc3QtY2xp\nZW50MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALd1TK3OmeqPFboO\nHYKLRvh8HSIDwPbnUvR9UshkT31cJcc6a/higVQjBPNswSJPKaBeC+q/IuAz36+5\ndE1CLjnK3XXUEpZJ3mFOOwiv6Zi5N2BFwIQO00zCYSD7d2JsepKZdzGuDni0vlxE\ns+SjNLU3n+Lu0GA2ltBN0C2MU9FwY9+XZexzaj0hfsl3Ql1mxzJBfPGZtpPauPGz\n5BMCXsnvj8d9+NFVXA6EhUzXxW4+WqIWaHOGsqOPf/nyb5DfG+DLaydJcL0kOwEa\np+kVctCDXWlaxCHZ/uTV6tx3hGEmokdQhr59WJK3lIA3fzgrKcBn8wmMPJO8zBn1\naf/kNNnnun46DF5WewHP+h7sRSk+ggw5KNsc8rWYc5o2o4Jayp7btIjgkugvCxN5\nqUyyPxkfPkIYpj3R5DnedU0ppf0EGajkSp6IyN1Bo272qU4iEB+dfsRZdRRYS+C3\nC7M4iKFpwZ/ZcMYKUEnBjuiBwF+vK0L1u0MkFDpr/mDAr0OlGZWE5VHri8dNRjE0\nk44Bs9pUBkJh0PrPOX2ef6hzsLjUqdX8gb5w8W61v0QF9Xel6h1u/XO+6fMZswIv\nBfdW97h0+6SV7xtc5+SNp+uf57IfRCrMw3mv21FKw4YbrPrRyzu6A5AxYmKNxPuU\npOwC95n28EClfjFa2BWsQRyS3vPbAgMBAAGjeDB2MAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFKKvs39cg9gXBOMojbExGCVSMdpxMA4GA1UdDwEB/wQEAwIF4DAWBgNV\nHSUBAf8EDDAKBggrBgEFBQcDAjAfBgNVHSMEGDAWgBQTvTgqEYFsfGGqd7S0QS1N\n/eV5eTANBgkqhkiG9w0BAQsFAAOCAgEAAYFFzp47Pbg18uVUYyBiEoJmp9RwIZUm\nyrywuLiOvRc6g7jgtgBdUmMhykIfeUlbDfiYlLy2+prRUi7RwCHJN+87itEh5yU/\nqpaBgS/oexi3LJRYcTw0SlS5jk03xA5WH2jXJ+Pov0aD2tVtZvvGS5G//RzC12Jz\n0Rd8v3RcK/azhf6UjIZcnEV1soBlu1YDaSDWcBYDuZZKzO+W4zqjSyKVLt8k0rpE\nFvzyph6YSpN5ag3f0aJjuG6qD3Aq/60SbHMnNofLbp1KmLwaLwHdqFmyJApEfmRA\ne1OMryM8QiuoSKTn0JoD1AbxBG+RXAC5YGlyTcjU7ZUC0pOM/UPvtQA1a8btRyrg\nmlsXEWFmM9NGT0sHdQd4BIFjBRuT2LK7Zni25ReaVMCk9Q/KT9+DyyKkjWx7oV0B\nYPxrNrW3wBb86ZeT+40/MwTi0q2a8EzRvCL6iMHX6LaJE/+7K28S6vk9ei6ALzUe\nbdr4a+UcZhNFK17sdGypOVln+N5TvWNXYYXtoMqAlqGEWYlVtQtLHtTaFmq2UzQV\n+OIbMWGVa1aZLn9VPDyAX231xtKnM/+mO60e5lEtjyNuv2jwxpAJw4kkRk2fQSl9\no10OWChTysmQda/rBgh3u2srOEYExBWid2RzqNmaSN8WPc3iX0Scw1d4iaC1cKF4\nvlnCk6W7k5w=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/data/tls/client2.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCS5QyVoX2R4cXC\nUU93PnibomqTYDHwPBTcBUaSQ3CR6ALw1XzK2R3Ze/4itXmLPPrs5aE5fm7U1YgN\nnmznCFTHorr9FsU7HT3cuh5VELRE2k5qqlJex8Tx+0Xm4y1R+JjzX9ZoJjCXJ2A1\nmxmMygUZcQWrwQyGTq4xKl+CtKxZxPVU/98fFknoBkOsBaux50+Kgw4gdvpOBjm+\nQ855Wa18WysSttbY2NBL5aogWL5bCzYJjhsWx6OU8LKgm18OzHVf/ZHBKyftfXsC\nxQzPWONVFUIkyvM4vMkPPnM0CFOn8NclYqL6qor0oaMUY6i4NYB0i5XtEhJB7XCU\nhmNeQ1DHaXFoK5rG6o23CyTnQgR1FmqJqv4YqZyunM7YSD223Y+3Ue/YtunVjwSy\nL4QZ7pedRaWwVaFhz8oBEwJu81sEvE+D9EFXnNOO3bvXyGt0kmLyTb/TxEqZ2kPe\nkoLny81coY8U+sOJV54rWRYMPD3AzNNPyw5ZnpPDLN0UX6P8uMqOB1BPOBOvIZtH\nIdOR2H/RkJ4LFtRPCHYdZ2SSlezowjqYE7tCWskjldz64YWkamgNvYLFPSA08BMQ\n6YiQzKEl/9+92OdvRDEsELzaGZZL2sID1nyLWHengxhH//BAAiYI1qGhsYxzdyhI\nYObe/QwfX/axopi2jpkK48RZ/4OFTwIDAQABAoICAEXNPaukr2yw4i4yQRaiwuEB\nzq71WQWVJzxd7Wj3TvimTS9v4vrpLPv5pYuMvJLjiUEk5PXTFItiZGJEU+98z/yF\nYWF+fn5WqNzIPD2j0GWfbv/Uq4uKVhW+lzrd3N1Eyjlr4xBehVxuQ5N1fjCelsm+\nITm6ZF816CRIxFXx0KxfoUygwb+d8cSlpWaK00mYZv2kxQO8Rbjp0GqPAgA8Euoy\n0Eb2RyWH8YL/QVZZlSriKu1jb4/lkd/meJtE+Wio02Wnsqkd/r0lkVyBklK9JFl7\n3pBpOCZP3yK1RD0Hb+kv0qxbMKL4g0s3u6ymprfSBJZc9gNPQQm+8G5DZdiXGDzR\nZa+RxPoUtJlvcOSUm2AlCRlTqhnfCp2qLiGLNrUWji6qgsuANDheIM8R7bX0TPjN\n1Y3GGMDMKyPC7hp8CCg4jscAIOJ1Ss0pAvf9vVPCBFQM8No0gDGc7GHNTTqb2lln\nx7JS9KPYz2NL7HLVGxRnyOrhSNhCB5Q0KJhSNF+Srw1naDyuDRMld4+7sDs5C51C\nTGQI51BeCcBF9PZzF3+qX5F5O1n9E3wsTU7sg5dyau/ryRXo/qbPSTF/nZFc60sG\nMNnkS5GpNC2PxtHocXviiGPc7NO1TgoEWalhmila4b4i3VHRZdl6BgERKIUyqyot\ngGv4HOHZ7N41bGlpwVoxAoIBAQDLcuzuwuCTOEy5JJEhhNkEr+2tPACg11lPM6F4\nhE6LBI5qjU+l2TK++H4jC6dvhF9KlWszzEQ1Yspprgrh8ZmLYrbiVimd2Hv27PYJ\nGxBxnaQl96vrhmPW/qNGSkyEEX08F9AVmGgn/2mX/YHsQSzG+U1cgDrnGl8kGQ1d\n+4AYGiBrMowIZXtcb4qyJinx5guJb3mkg4AdswDEhXj96TieNhKVrPQRG02RUSE1\nkgYa6rgwHC7jJ6BZ0WsS2yNj2D6nO2UXQ2V6FYINauCmyPaMIpqjUzby5UCgNgqe\nD2kqNNj5l/cAWC4x399xy7zLkZd15VhqWxNfuKPSXFsveuPFAoIBAQC41nkSa+ru\nRW8Fpb9RxZ/6ke6IyVTnvLqWp5A9CYVpjOBDOk38kMmX/cIoN1eyoD715fArO3gF\nIzLMGmR6WSgbUEWKdrVFBlUC/JQ9Tj3Th/KWBs1cnljK2Hg64k83UWynoZIL7ZGQ\nQ/x4WOqTvW7cCB7bOzI9v2kIzvkXSd8qT2TLNKnuR+n+6++Sx1/3P5OjPbUYlkbX\neeHDmFGj3mCqtQgGo7GJmvOhIgbvSft7BY9eZ5OF4TxuiQ9uat3tIMOPD+bgvBuj\nSuii7K9je/cE1YOxDz/UBfyHA90LkVcKW2tO9e6i3tp0pzLd9ivzCI5i88JnVjNH\nvuDw/wv2wxIDAoIBAHAB8MGulpdWyp6vrBtJGXXEKdVTEIF8rhW1tjM0nE1bD9FH\nxU7omlCbXE6NDvyNYy0bwC5/ShoeLpQqFqG4MrGTgl5v02+sjOswIHB47v+uK34f\nsg30KilmfZuoMiIPwuP/tDb/dnB25Lqh/hKE+1L8VAQWMNelJDYqeLqCSU57q9d4\nt7GztUv5uOFFs5gS780Vi2HwZ+tx7n1Dgo5ABUTNPkQbOS/l2Tmk8eSdZTESgp8y\nFPpIibaJXiq+bOh+WFgXkhtRpp+lEbmzWsVYJKyYLIy4tqrZXlAWEJheoaZz+/TG\nHl2ZLq2UtF7hLSriGAH3Z0r+o1byv3aEFEu6m4UCggEAXO+5wIFyhoty3ywPnlX3\nsk1d2nkgr8Q9LTLjW01GP2QN/r96JtvGAR4eWYo6Fh5siccrkxE7r5mbGPTMQJhD\nijg6Pvyg+CvO4smM36ZPf+SDHNwetcsIajWdfj38BpxyPXcHr+eroRYOA5TxnYdK\nDmgm26RQBqwPa9ZleEg0ZVm2HFZGewC9rueCdhK5NeBJo3KLc+lbhUxLL8WOhw5x\nHGQZvPzhb4bxqLsrMXXJdHm/NIBvtIkjkZBoqeQh4fDvYydjtuveGaS4g/Lt3N+f\nvFZ++K/qL/kyl9BhfEd/tD1zHyiY7FuRC8Zl1STJxFExBp/5x2uYLSLUh1g188Tx\ncQKCAQEAjx8JRviB6JCimQfXdNbJxaXwHUs7ByFrGpYbNfz4vznMumIKal8Uik7w\nioCRZdKIdQ6WECNFIaH+xmQHJSAaRGBATSVwXmegQPpCoS0zmAKY+YL+Q/zfkP/6\n58bEkurf4AC+GzBIO1/g1LoW9lAFN/MJrd5p5X2VM1Cw2haB8bD8aHim3KRNpLik\nf0khbIGLDqRlabyhUMBwBq4aDzYHlUw5YgKBs5baX88jJGzXlpVlTG0jke+FXnWt\nv7WX0iNidzkVQSOkG9qpEphw794CwSQf4XURuXkMxcxSLAuVYWyD+rjMdKkhqk0Z\nGRmcc1cjoz7e2eepBp+mnRIotyhjbQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "examples/data/tls/client2.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFRDCCAyygAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwKTEOMAwGA1UECgwFVG9u\naWMxFzAVBgNVBAMMDnRlc3QtY2xpZW50X2NhMB4XDTI1MTExNTE4MTI0OVoXDTM1\nMTExMzE4MTI0OVowJzEOMAwGA1UECgwFVG9uaWMxFTATBgNVBAMMDHRlc3QtY2xp\nZW50MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJLlDJWhfZHhxcJR\nT3c+eJuiapNgMfA8FNwFRpJDcJHoAvDVfMrZHdl7/iK1eYs8+uzloTl+btTViA2e\nbOcIVMeiuv0WxTsdPdy6HlUQtETaTmqqUl7HxPH7RebjLVH4mPNf1mgmMJcnYDWb\nGYzKBRlxBavBDIZOrjEqX4K0rFnE9VT/3x8WSegGQ6wFq7HnT4qDDiB2+k4GOb5D\nznlZrXxbKxK21tjY0EvlqiBYvlsLNgmOGxbHo5TwsqCbXw7MdV/9kcErJ+19ewLF\nDM9Y41UVQiTK8zi8yQ8+czQIU6fw1yViovqqivShoxRjqLg1gHSLle0SEkHtcJSG\nY15DUMdpcWgrmsbqjbcLJOdCBHUWaomq/hipnK6czthIPbbdj7dR79i26dWPBLIv\nhBnul51FpbBVoWHPygETAm7zWwS8T4P0QVec047du9fIa3SSYvJNv9PESpnaQ96S\ngufLzVyhjxT6w4lXnitZFgw8PcDM00/LDlmek8Ms3RRfo/y4yo4HUE84E68hm0ch\n05HYf9GQngsW1E8Idh1nZJKV7OjCOpgTu0JaySOV3PrhhaRqaA29gsU9IDTwExDp\niJDMoSX/373Y529EMSwQvNoZlkvawgPWfItYd6eDGEf/8EACJgjWoaGxjHN3KEhg\n5t79DB9f9rGimLaOmQrjxFn/g4VPAgMBAAGjeDB2MAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFOJW70lD3qk02xQbPYugfe8r+RJtMA4GA1UdDwEB/wQEAwIF4DAWBgNV\nHSUBAf8EDDAKBggrBgEFBQcDAjAfBgNVHSMEGDAWgBQTvTgqEYFsfGGqd7S0QS1N\n/eV5eTANBgkqhkiG9w0BAQsFAAOCAgEARvyLPHAioCTNYvv88yJoDWnbfDMpOYFJ\nCDcxGgat2KSuF9LB/Rua58VnkbvtkaymNo1SfGNLIXL83bRdmFA1CgW/sxqnYUpG\noh8UfQbRV9AuJu0RrRubqFZ+MOW70jzs8LvUZIFQtBjz9w2zpmRuxKZOAgmvqXLw\n8FKZoi2P8lktRw2ie361Z1yFSV/UCKWrIBYFpb8W5/+Elb75B/iRl7jZwGO4WuCV\n/8gYgP2ScWuHP4LfkTcifOYcxRUhZ856N2uEGL3ywcKuvjz/EaK9NyTQb6PTyy10\nz77fjtCqu6uAW7y2cXkw9paLnp71GF3pglvgXzngpYbJN6wgZn/BNPKP9V8/pgR5\nhJkezxr2e7cCrERp+a3eq2CDsrN7SDKgAJh0ZjyDg8Iuc/rP6OwbTqPyvU00bWi5\nkFCp8qkOBun2v7eRpRfwjXB55O0iZID69xmy3UwX3E9as3ftzHnIcTGeiD3OoX8E\nhw4sXLlIH9Cgo4lIpihSWGPkJC76qikXu80IVUquutJFEnuOkAF/oXrhl14nSfAI\nhDQZwebh5YYC3TFQqjyQbzBcG8QFVb53YWsywEW3EpRp9Dm7qY4dmlG5lGmY5pKh\nPYGfB6tvLLU/iNoOgOVw15enRrPcnYHWKrUPQNexYzfvBywR8tVd3QcXBa+XZtu8\nNbP1BZHBSuE=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/data/tls/client_ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC0Yc8MUU0XaWXh\nI5IpE5BD7JYWmhDGZnZY/YdCgkwo/EZ+MPi6OuCWfS/9U7Z3q0AeBxZ037Wpu5Dy\nrqkgNMOsWZZjnHQ6QDjI9ieanZfCsg4SN45hO8JDUtOxSyi4BpdYuLo+N+G4x37n\naf5VBg5vqzcgYnaubjasvBApWNgVInyzMuifU25nxzGN66zZEd/dJZYFNvTxm9O3\nCWj2ZMWvQ+3jX0Z0XnWqkcoekrmAzPFaBLkBm7pGKFfOA+RBB4yxSh10K0TXocp3\nhzqNqvxBMxO3w5e6eK9yQIAyEChqo3I2cbE81H5k6M2zPWawCuegwWniHRVCdW23\n5kNETkNYEfrJOpE8TQkbEnri5oh9rrGREMqiN8UKc2mBbkyq1rOSwVecSyuDskaT\nmBEcx4WuBKbocbG7bJityvCJkhFnzXLiMrTzbtoaq62g40QF5Fg/rF1u7oAyEr17\nAP7Mf5u9itkTkYphGJMnOcJ7EM8h+32+wR9GJljAeNz4gDDc0wg7S6c8KPL/lXLH\ng4ekNqu9PGtHqoq/qeKPzA9df2gss+dMVFm2j8YQ6Ohay4u4v6VFsiHGUTwBr8bL\nFp2HAK/hKZDYyZZcKqOwVXuU6ur+g5Et1w1iIJe8MSQ2egPfjoFziL1wbPj9s6IL\nqqIo3AF08h8zSU4I+PqMi5IAukkVmwIDAQABAoICAA728lNmR0wC7XXRGqYXvmc0\nMHttiqi7BWR6nAcTgjgAPeToMSpaChnSBvIwSLoC1g3nrqBBkvOi4PKRNOy8E+Ov\nhv96klXm0A80BLMaEeYQGYS/YSuF5qbpLzDNOHKT8Whl4uWYgzxuKIQQUg5Bs17m\nSGuCX7A26ohIDdswSLTwKIJBXfUh2c34Q48vlyZnCjhxjtGd7pJAyD6uJCwUziWt\nMAYl+FVdJMvizm7c41DhL8C1FZghkEGTxT0NK5mNg8mNiYYCtPJitMZXzK7GGalb\nEG61ZlgM/RkwarI8ju3R437KzdZrFpVOjwootOUz8mVuxlcA7KuXzGNuUfRPvdxj\nyurNVZkGynCC7g+FYhUMZDIJU7YCFEgXmBr7bTleMEccGQIroW7zTXy8dhweaI0/\n7ehhy6qQObPxCehGYEXY8YThoPtpQbrKP2Y9PNQg92tZym+Jifb602MrYeSzxp71\nSWXy6LSrODo+FpdKW6YHclRJx74Kkbp7Ux6oKYWqYvIlzAPOtY1FtMRBM/9p9AVI\nBrouacRZpTP35Mt6Mxg9JpAxBOGviebS3SoJvGD2Bmq1ALb8zwYhmT9M1whgrJiG\nH3qOWyS9Koh66m8Pny7V/XMh5KcLky+u+DN79dkdnzf8MNAzslr5vnBg67byvvVX\ndnH2x1DXkTXI6bxLIjhxAoIBAQDrn/E7YVJ7R1dSd9Tn/irhL6mkRJrNroMX8G37\notdhvkBiuLiTOcjoukINew1/GmzhrPnsWXx9zWQmpbtTOTfTRFIQ+UGw8LwAHBNS\njhK+J2u9tFFWJ6lonrLD+HxhdkmauvcNs07Ol2jNMNpqBc2gQ+CdzljGZcSekTM9\nasmkXut65bEk3tVhV+MylTEyGlGuMaR02mSLcfmIApOUFCNAi+kvfAs7qRUKjCBu\nNp4SE6k6mY2/cGj2vjyDSTYdhgnVv/evyZU/5YWAclTpKS92PuJyLBQXwqcyU/FS\njhEUFz8PCA2DfYPLjSUPNSh8yO5oR3kXF89MB5SvTWYVH0vZAoIBAQDD+vN7hO52\nY/Uf5Y7wStU0kIb4PGtusEyyDXXIcTFTEuyN+34gZaACK6bQd52YhpRoLvtLeai8\nxwrLtZRFUP8X0/rpwXvdl9EWWRNNnJnWx6wuzNZncrxTj6UHoKclYdP+ypJmneIf\n8QipdROKcbvMEkgq8UJlL7iE2xj23VfKAyvm4NNyATzWQ2L5x/8xCu9X+6oHyJ2h\nW0aYA2bCSl0n465/1Ix33riAVR9v0S/Y3ndYJ142c0Sxt6uHTpvEFrcieJA3hklf\n1HR/rOr4F9u1rueO482fok/8OrUdOiWEDS8WptGVmRujXYv/wlNEPuC7qx4xliel\nyi0bhoNYJ8iTAoIBAByaqhpfUjgNDRjB22LehC4aLyn1+iUGDnwVgASQXD1Nb1uM\nuTuGRFGcavBgA99uQdGTwjNjGa3cBVB7xiXwSEqpfJz65XKphuksf1wCS1wyRO4e\nudEPt40v1tvbip36Ui0qjVtobSS/VMW0LI+6bKAMHXSK3FQZfqkRT3shP6FotIWS\n5NJpCtZqaPZ3DiXa9BeFh0V4TcRv7a8JQQk0+KKZWZGeKW7ws9E3+afnkYD4Sg8H\nHSIkb1mk9oupk5w57W+5gkQg4LGFF5PkTVKQ4WYldDAQEdBgnROLBTzUalZaDBmz\nDJDt59YKKHmUJnofmnGmW5jmFxBPy0kMyFvAFOECggEBAKHP7v86Z6WqrHaUlGuE\nbfsDpd0KDe4LdJfCk1BXXVFpG5WzY5UeM3n3TrlrOdz4qUpIGEZeAds0QI6nsu90\ni9rBtLcSgNIaipF4JH79YOu8W0cc653oVuRrgugEVl2AI4iI+03s6ApVekBoISU6\n+MLrCVkjcB2ZxDE1sawKX3S1H6d2VD8aFIAYjX0NC4ATtkCf0uiwVK4obeYPUOX0\nfmv0Cl0TQpOqeg3DurwZLPdT35gSkTBGBh7yNpb2aZgC5Vx5zSF7J9QO182fGTaU\nhFzDN/97yYgXfREV6/pgyx73v7xlKkDpdK9zCqe2bAe6HtX02G46uyug/ZNvgbzk\nxC8CggEATGFt5dV6TZUJPC2k7BNev/VwP6CK41fTRVGkaMdiM+HAcHYAOaPoHvln\nMwxfQTof3KkgttA3/94S9l0IWO6kda0nKaNwcW4IHfmqQ0moqpOeHgz5XaxSMhX/\nFwdzAkYUeB95wCjI/nY5jAA++0sejs1E0Ao1nmLRkAg9Whe4uRrcqp1u02vZQ5kk\nGq+xG2VvQCGOyTocynVzXXsXfoohDKDszKNxQX99UZ24bAI38oundxqFnYTgifnN\nNSwNyDXlxK20CphSkAzt3Odf/Lr243Bxm4d0C0H29ZKceuReMDFBeUNStt+oluXy\nUKS7m+M+WmCsNX9UkKWh09Ks6KVO4Q==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "examples/data/tls/client_ca.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFijCCA3KgAwIBAgIUP0tYMykcdcDwKamtdfqbDg//4O0wDQYJKoZIhvcNAQEL\nBQAwKTEOMAwGA1UECgwFVG9uaWMxFzAVBgNVBAMMDnRlc3QtY2xpZW50X2NhMB4X\nDTI1MTExNTE4MTI0OFoXDTM1MTExMzE4MTI0OFowKTEOMAwGA1UECgwFVG9uaWMx\nFzAVBgNVBAMMDnRlc3QtY2xpZW50X2NhMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\nMIICCgKCAgEAtGHPDFFNF2ll4SOSKROQQ+yWFpoQxmZ2WP2HQoJMKPxGfjD4ujrg\nln0v/VO2d6tAHgcWdN+1qbuQ8q6pIDTDrFmWY5x0OkA4yPYnmp2XwrIOEjeOYTvC\nQ1LTsUsouAaXWLi6PjfhuMd+52n+VQYOb6s3IGJ2rm42rLwQKVjYFSJ8szLon1Nu\nZ8cxjeus2RHf3SWWBTb08ZvTtwlo9mTFr0Pt419GdF51qpHKHpK5gMzxWgS5AZu6\nRihXzgPkQQeMsUoddCtE16HKd4c6jar8QTMTt8OXunivckCAMhAoaqNyNnGxPNR+\nZOjNsz1msArnoMFp4h0VQnVtt+ZDRE5DWBH6yTqRPE0JGxJ64uaIfa6xkRDKojfF\nCnNpgW5MqtazksFXnEsrg7JGk5gRHMeFrgSm6HGxu2yYrcrwiZIRZ81y4jK0827a\nGqutoONEBeRYP6xdbu6AMhK9ewD+zH+bvYrZE5GKYRiTJznCexDPIft9vsEfRiZY\nwHjc+IAw3NMIO0unPCjy/5Vyx4OHpDarvTxrR6qKv6nij8wPXX9oLLPnTFRZto/G\nEOjoWsuLuL+lRbIhxlE8Aa/GyxadhwCv4SmQ2MmWXCqjsFV7lOrq/oORLdcNYiCX\nvDEkNnoD346Bc4i9cGz4/bOiC6qiKNwBdPIfM0lOCPj6jIuSALpJFZsCAwEAAaOB\nqTCBpjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQTvTgqEYFsfGGqd7S0QS1N\n/eV5eTBkBgNVHSMEXTBbgBQTvTgqEYFsfGGqd7S0QS1N/eV5eaEtpCswKTEOMAwG\nA1UECgwFVG9uaWMxFzAVBgNVBAMMDnRlc3QtY2xpZW50X2NhghQ/S1gzKRx1wPAp\nqa11+psOD//g7TAOBgNVHQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADggIBAGTV\nHtsZUI+XI9LB96T4xV4eHdk1hOt930QOS1pzdKEEFJhZYD8PlII94MlPYhpFbpTX\nU68XDA2zXMfKnNWp1WsOWudEGxy0MPVVOER6vc/w6qfdGi7vbxLB/pqGwifKAiPm\n+I3XcRXbLF1W7KbbsT61u9gecSWK4WoZUPY0Zs3hrDvut4jRVZr/egXQVvYp2gGs\n8oTiVLuT2rYIGrDYinsQcY8DQJUnJQZwZM+hErNpylzVXRfM1nv8NzB2QQGzT3Pc\n8GdNXD1iGUywjo8/LcEvp6HzSrFeqli9ZkT62yaMZncv3iw/8yxmrCClW53xTj6C\nAuXhPsBbLKxODM21BBkxxWFpOQc3U2vzgcXpo60DWfMBAnayDwXiCuM8tdRp38kH\n0dEaAMMZHrL9xm4Lfyzqg7siIb5xn+EzZ8EXPc4WFXT257lraJp9mLHWHSWozJX3\n6+mUXe/9qwfiyL4vYpSTXLEcuYim7Nwo5CL0jkERKNosp07USSDFWwZKHI91Hd/n\nHIlusaYwAVuZpcC6Xzj+0/kbl+ImfSTtrEATNFf3pEa37BW7nx4piB3j+xXyW9Gs\nqnZwBTq2q8JEUEhO5jGd+v6zrPWMx1ndHrfr14wP7yzgpIv991Qgr+4YMMAgx5u3\nw9/u28aPz0wbD3HuDWwxmUoX+5uEPw4rxFc5k3CO\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/data/tls/create.sh",
    "content": "#!/bin/bash\n\n# Create the server CA certs.\nopenssl req -x509 \\\n  -newkey rsa:4096 \\\n  -nodes \\\n  -days 3650 \\\n  -keyout ca.key \\\n  -out ca.pem \\\n  -subj /O=Tonic/CN=test-server_ca/ \\\n  -config ./openssl.cnf \\\n  -extensions test_ca \\\n  -sha256\n\n# Create the client CA certs.\nopenssl req -x509 \\\n  -newkey rsa:4096 \\\n  -nodes \\\n  -days 3650 \\\n  -keyout client_ca.key \\\n  -out client_ca.pem \\\n  -subj /O=Tonic/CN=test-client_ca/ \\\n  -config ./openssl.cnf \\\n  -extensions test_ca \\\n  -sha256\n\n# Generate two server certs.\nopenssl genrsa -out server.key 4096\nopenssl req -new \\\n  -key server.key \\\n  -out server_csr.pem \\\n  -subj /O=Tonic/CN=test-server/ \\\n  -config ./openssl.cnf \\\n  -reqexts test_server\nopenssl x509 -req \\\n  -in server_csr.pem \\\n  -CAkey ca.key \\\n  -CA ca.pem \\\n  -days 3650 \\\n  -set_serial 1000 \\\n  -out server.pem \\\n  -extfile ./openssl.cnf \\\n  -extensions test_server \\\n  -sha256\nopenssl verify -verbose -CAfile ca.pem  server.pem\n\nopenssl genrsa -out server2.key 4096\nopenssl req -new \\\n  -key server2.key \\\n  -out server2_csr.pem \\\n  -subj /O=Tonic/CN=test-server/ \\\n  -config ./openssl.cnf \\\n  -reqexts test_server2\nopenssl x509 -req \\\n  -in server2_csr.pem \\\n  -CAkey ca.key \\\n  -CA ca.pem \\\n  -days 3650 \\\n  -set_serial 1000 \\\n  -out server2.pem \\\n  -extfile ./openssl.cnf \\\n  -extensions test_server2 \\\n  -sha256\nopenssl verify -verbose -CAfile ca.pem  server2.pem\n\n# Generate two client certs.\nopenssl genrsa -out client1.key 4096\nopenssl req -new \\\n  -key client1.key \\\n  -out client1_csr.pem \\\n  -subj /O=Tonic/CN=test-client1/ \\\n  -config ./openssl.cnf \\\n  -reqexts test_client\nopenssl x509 -req \\\n  -in client1_csr.pem \\\n  -CAkey client_ca.key \\\n  -CA client_ca.pem \\\n  -days 3650 \\\n  -set_serial 1000 \\\n  -out client1.pem \\\n  -extfile ./openssl.cnf \\\n  -extensions test_client \\\n  -sha256\nopenssl verify -verbose -CAfile client_ca.pem  client1.pem\n\nopenssl genrsa -out client2.key 4096\nopenssl req -new \\\n  -key client2.key \\\n  -out client2_csr.pem \\\n  -subj /O=Tonic/CN=test-client2/ \\\n  -config ./openssl.cnf \\\n  -reqexts test_client\nopenssl x509 -req \\\n  -in client2_csr.pem \\\n  -CAkey client_ca.key \\\n  -CA client_ca.pem \\\n  -days 3650 \\\n  -set_serial 1000 \\\n  -out client2.pem \\\n  -extfile ./openssl.cnf \\\n  -extensions test_client \\\n  -sha256\nopenssl verify -verbose -CAfile client_ca.pem  client2.pem\n\n# Cleanup the CSRs.\nrm *_csr.pem\n"
  },
  {
    "path": "examples/data/tls/openssl.cnf",
    "content": "[req]\ndistinguished_name = req_distinguished_name\nattributes = req_attributes\n\n[req_distinguished_name]\n\n[req_attributes]\n\n[test_ca]\nbasicConstraints        = critical,CA:TRUE\nsubjectKeyIdentifier    = hash\nauthorityKeyIdentifier  = keyid:always,issuer:always\nkeyUsage                = critical,keyCertSign\n\n[test_server]\nbasicConstraints        = critical,CA:FALSE\nsubjectKeyIdentifier    = hash\nkeyUsage                = critical,digitalSignature,keyEncipherment,keyAgreement\nsubjectAltName          = @server_alt_names\n\n[server_alt_names]\nDNS.1 = example.com\nDNS.2 = *.example.com\nDNS.3 = example.test\nDNS.4 = localhost\nIP.1  = 127.0.0.1\nIP.2  = 0:0:0:0:0:0:0:1\n\n[test_server2]\nbasicConstraints        = critical,CA:FALSE\nsubjectKeyIdentifier    = hash\nkeyUsage                = critical,digitalSignature,keyEncipherment,keyAgreement\nsubjectAltName          = @server2_alt_names\n\n[server2_alt_names]\nDNS.1 = *.test.com\n\n[test_client]\nbasicConstraints        = critical,CA:FALSE\nsubjectKeyIdentifier    = hash\nkeyUsage                = critical,nonRepudiation,digitalSignature,keyEncipherment\nextendedKeyUsage        = critical,clientAuth\n"
  },
  {
    "path": "examples/data/tls/server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCckNy1wG9TFgHM\n2LlY2YnuaiqqYAyvNtzOH7Dsbgodhj2pNdeiN4siNjmL5QwgXuVJ7V8EyYBNIvu0\nYjKWOtmcaXGEAdIBIw+aqfBKkrLOBNhkgG55W6bIALtbNpmLNFJ2QNOslH/Hm/fA\n4r2Y7TFNSp+dHjUMaq6jSwMuC/Z0bYDEGrnHpQ4Ml/jYivB1i2n23SJBcDL4y39x\nLJ5abnWDSZkO+sGe4Eu0UV3JkLTPOmIHtwZNzC8luzhdYPiFvwJqLJKOLRmWIQoH\ncV4/Lsgbuq3KoSmeu3WrrVbFHrZr0Mk8O1WwfOI6ufpIIi89FqKU7+MwC/SiGirm\nFoBDdgIeI5sATmUnVvv6yv6Dc1xVRIwTCkY683VRRdtrt4YGWcd7PBm9wKPbIYJS\nSurE9skeTNYhBpA9wuosOFPO+V8wpUsPl2Xb+B9YQAj0/oeNZSbJx5qhQftK5PvJ\nEB3sfRqOiiIJmCCrxL30orvx3xHrOL91yNav+QLhra4tDMDJ9kq5vhLtikCS3yyB\nDFPldAGWqRle8j+I0bxWq3josocrWGyRxFgNsmVoxHlr0gRRA+sv7Brw283qh0ub\nQfIJWNco+Yb+e1ZiV99vaNHtIzEVxO0NIqL+kLPtN9PrNmxGAkO3HZtQZec8p9wy\nItbq59JNYbvJEe1VrMHkOrQmAinLCwIDAQABAoICACvU5G1fs+rrWNKsA+vLbzGX\neF1daX+uGM/+EE6Imf1dBSs3nyhTa3jG/IJdO/FeD8wMD9NrxCcUOaps6WOkkyKW\nZIjD57KYybgPhm2iNzu1II22ZPdFwOHyToGBPig6HDHuATSqGEHeONS/xbun/+r3\nDstyVwCkZ0Lg78F26Ob8dxWvs74gR9gfvbOF5j7KKn7JttriGesMMaASET0Y+n4o\nXxjR+93KRndzZhHVmMEBQ8uMIlAqbzKdgPCngrwS1w65bsgt+SFOG5ws0WlX4/7b\nWudFCj1dltpau1WRPRnfCE97/wfbVoyBX3/NTjNIgHi41f4wAqtVLxheSUdZpMqy\nGo08I+/TEd01pp15JjlMZVA8cqLbRpqXK1JddNZFGItWoLOlYBIg5+L4Hw/RyIRe\nbpBP6XXbTSaYMLyEwhrKuaX2kOfPqPMGBMRIil7r0uxHbhofX/1EbSUzemgxf7Nf\nXZTlxvCF6uAbDlZPoaenMv7TIueUZGUyUSjigzFDV/eKgoY2LGNiO0m3jobTYHlN\nY8phN/WYYHXNtzjFQGsOXtxVyCt/Ana2N7WSc6qg2HoZI/1NFHOtqMRUN2i+WTH9\n7+1sqi8lGQHbCqimb0o4Fm8vVlAonSsBOwt2J7PJdi0O+yntAPwncc2lsMzKTzbe\n8WNok6VKQS87n1TjQytZAoIBAQDPjcMWvbCnpojY8EPzSuCJUpVP2pUxSEAJwk3U\ncEJKIIqz5FIU13hAnyMpr7qVVnNg8qZrghaxpYSYiDo1YqYeUI4h+c67c8QjEge/\n03NNBqZjZ614zSZwhMHztt82VqS7h4Nb6dV/OaeM/+HeBQTuQId5tAle4yYoXhpd\nRp0WT16NYDR5hQnbquCT41f+TLWtmEKktfgbF9DW3hpT4FjLnNC1gEcliGd9mUMK\nu5m5fvf6EGHg/vXDZpTPJaC95x/zAvId9vuLUPTIFUCJZ8vvhWFmHFUi4mBmPirX\n+oht+tBAVwsGx2vsq23GEPerQAoGCn/1OJCxgZtKPni6H0spAoIBAQDBHFox3kjt\nKchgU9fZCSsw76+Hfo5sb7GuimgOeb+1cxIdO0iwsVwI8Ft6lZMQoqDj2kmeF9wr\n/qlnyKtFh7E2w7B0tJD/9vaZjXIn0ZW4hdNBVuh2o/x5ZgR43dneUpqd37hJPAe+\nTt5LEC+mTS7yD4DIy0gvmCFlAcfcYiiZDmkS2iExWJEazFohGveoBDD7qBH06wWH\nbrJ2lUKTkntckhm/T8CXAfEsOER8kCyl46KEB1tuD/yctXP+FiSdyO15Q+Ue/Ok4\nLDzUeyDFWRIH57nxkV0dZ1iktj61kEqHWBF7KwSCZ8LUA2JUaMQqRajQbOsul8qO\nl/b/MzD+u18TAoIBACu15UIizNNh5Swa3ZSdTlBdTgi1NfpdBu+HNjDpO2y1EcD0\n8rxk7HRfj142HgtZW48tSxMVIIZlH1moRun7TpTPzj8lhv4/US05nNwvQfcU0XHZ\n4dSxD8lejCIxfyzIboT38xgmVMoocDrnoL/LOtCaUm21Fswe9mhF+TNvraGHMZiA\njEyTUhIrGITMujlaGmDm0hIyKIA8McUunUjQ1KJ88g9nZpRm97Sh1FasT6GbNco6\nLQLfbw6pyekeOY4E4Nui4S6iVzNt5z9ECoVlkLNu2aZRjTR9jGO77/XwU08mJTmH\nm1DgKsB7EfFGnYI5SGMhTvVr5j0b2IJ4SaCY+pECggEAD2hgtevja7DSwQTPiwyV\nOqFVIv1xBavfxGpcpRMHvcWBo31wblCoZDoxQlWe10vyhFuNViTXN1dpUtOK/tA1\nzoXMlXM2woWE5XmIqy6owIFE+sihYZ3x7gm6v54L3RZAKeqIvKcigwet6tVOx/kO\njte30c2OY+XCfFmpBad7T8L7lTp8PYCwiy/U3SFWszwqYFnnnOAHn+ewK4/7MOUW\nHKu3jDEjz6ijAoE2za1/Mnk4JUqk++IgqKw9pf9ESqaWc/97z34kaYv2CooMclKK\nAsF1b5XGlSsCwpmb5Uau+5+GPYqQIIuA2wOuG8gEJs9KCd824I/R5JCxb2k5Noni\nqwKCAQAGZ1xHls7zmCwoqqjAHyvCxm+BUEEus2EQsePshsM4ALaxlOD+w9pLCwTZ\nEyb6p9Nn5ZGfP2xawC+Zh43EDZHS2LmAnxx/dVkrUZWYFrvPq2I25c5LlN2aFmLN\nW5kDw9HT4vA7X+xztVdiha5rbCC7p2ipBK377R0ptfUvuF+0oEfa5irKkAtDgJ2P\nALtzUIiXvGPDfNFdd8omAtmqMkfzPieCbQeHyeDTWdU3rlM1P+J1rGw9qQHgQv7K\ncGVD98d/pug5eEfrPGnATEmK9tGEpSgOQ/yJ4X7ij5HxGn7cLdKStSbaJntBzrBZ\noX39ft84lbWc2E2utbbgdg3kIbRy\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "examples/data/tls/server.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhTCCA22gAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwKTEOMAwGA1UECgwFVG9u\naWMxFzAVBgNVBAMMDnRlc3Qtc2VydmVyX2NhMB4XDTI1MTExNTE4MTI0OFoXDTM1\nMTExMzE4MTI0OFowJjEOMAwGA1UECgwFVG9uaWMxFDASBgNVBAMMC3Rlc3Qtc2Vy\ndmVyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnJDctcBvUxYBzNi5\nWNmJ7moqqmAMrzbczh+w7G4KHYY9qTXXojeLIjY5i+UMIF7lSe1fBMmATSL7tGIy\nljrZnGlxhAHSASMPmqnwSpKyzgTYZIBueVumyAC7WzaZizRSdkDTrJR/x5v3wOK9\nmO0xTUqfnR41DGquo0sDLgv2dG2AxBq5x6UODJf42IrwdYtp9t0iQXAy+Mt/cSye\nWm51g0mZDvrBnuBLtFFdyZC0zzpiB7cGTcwvJbs4XWD4hb8CaiySji0ZliEKB3Fe\nPy7IG7qtyqEpnrt1q61WxR62a9DJPDtVsHziOrn6SCIvPRailO/jMAv0ohoq5haA\nQ3YCHiObAE5lJ1b7+sr+g3NcVUSMEwpGOvN1UUXba7eGBlnHezwZvcCj2yGCUkrq\nxPbJHkzWIQaQPcLqLDhTzvlfMKVLD5dl2/gfWEAI9P6HjWUmyceaoUH7SuT7yRAd\n7H0ajooiCZggq8S99KK78d8R6zi/dcjWr/kC4a2uLQzAyfZKub4S7YpAkt8sgQxT\n5XQBlqkZXvI/iNG8Vqt46LKHK1hskcRYDbJlaMR5a9IEUQPrL+wa8NvN6odLm0Hy\nCVjXKPmG/ntWYlffb2jR7SMxFcTtDSKi/pCz7TfT6zZsRgJDtx2bUGXnPKfcMiLW\n6ufSTWG7yRHtVazB5Dq0JgIpywsCAwEAAaOBuTCBtjAMBgNVHRMBAf8EAjAAMB0G\nA1UdDgQWBBQEPLfmP4Eq7TBJNBTycSOpAm1EXTAOBgNVHQ8BAf8EBAMCA6gwVgYD\nVR0RBE8wTYILZXhhbXBsZS5jb22CDSouZXhhbXBsZS5jb22CDGV4YW1wbGUudGVz\ndIIJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMB8GA1UdIwQYMBaA\nFJzRNbz3Zvy6BcClqEMaStF2MiPtMA0GCSqGSIb3DQEBCwUAA4ICAQAMvZsUIQ6q\n5Y2B1qrfOv/iXIoNE6/8XCvbtoTS6ULEotfhfVPdLVXczfEjc0lhwOlD9Hqwx5qN\n7Lmp6IUodCQWLP2wRlF0hVii6EuWJzNxGwfwjwdQoNEgwNUQkyRM7HQZPQZAx0gi\nhNRZ9uJdqtkaKsyA5vr4PWaOLBKvcWGOV3HVMPMwH17JKTmNjevvQ7qhOSfc9sit\nOB5noLofNUxaIe1xfKqhBk6ngAyTfSd3jm9W8ceISlOtbjOecGw4P3TQXoEwwHDs\n/crMfc/DJPoi6cn3d+1D6m9YaNhujVdzDwjytU+YL2If8hWnJPlkXjmzNe4BjfS9\n/P5IoBONAJ7w19TVN9wLTAxGOK7FJ7Z7/PlSWsJ6pzedZ5scOzJxmgmclWaHfGPb\nY2YJayTJx5ddZ934IDT2ws86HMfPRfhbP7HsUp3jX0I+0DAi2H2cM9OSF0zhgvJu\nafbIPr7zpoIfbGpAK4oVZeZyiR9KMA+fnWBl0OrGWeXWYbMJQlLvrRVUrBJhNVl7\nIdHrERmUaRg5nZa3CsgQ7R3JfCfxuLKh2iM2zqIgS//iu7a0fEFqkQ9DGiSO02CE\nLLzDOw7AoZ6FiDnG1LHXfOhzUU67IoXOCjXObSgBo3I6Sl3xKqpZQJ+eWYBrkPY2\nDiWiew41BFDk7bADyeN5fffYkQjJCs54DQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/data/tls/server2.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDDX6SRgoa4jTxv\njbsx8+EXOXe0J5gdbdp1nsDH6tqsLTcLAdLvxEL5Sja/VGfm/6QbgYiiFf4EfvSN\nhAbe/2gg14yVTxoZoGTyrqnPfJCd6GK6v42MpmG0B/cxYsWZac+daPI08KgYEO5M\npBHvWbZCPoqeFRofU7TBrD8GLbyBBZSi4GrCmFAf6wcdOddZi6+9a4K22PF6q5QV\nEaY/wQXhI+EBAWUDcfMhnSdHpHPLM2JD8DO10R+gLEs4Isq8xnAdebxZAfpphlER\nUlho688ZduSyB+XZ4hxKty6SqI17+qt6RvRdGzTDOO+NAjBa1dSFiDHKGZW2OSu/\nva4rD8ztf2hs2hCg++MGU56L8f4/GbWDnTXrpdqoC4P8sWBsNVfv7BVrL527O2Xg\nBFXJvCj5dBHwjHNM4kKzSYxaeJcD4HPvZl/143DvDWfdoI4WecihtaxYc7+t1NK/\nSIj8FA+FMENRrWzacwY2tsc64zdBrzyStGdPEYretYKYSNvG9AytCT7jI+yCZkTv\n1cLitWA4N27Si2ev1c8FKNWVgsEK9/WQTq58xgI2e+InGXNTYm75wGotPufK/Z/3\nch0h8JE81nbuBY137485cKVJLaevBsSfdcu2KihROwGHQs4AiRXxuf1gliwNBedq\ngddTIQRt5euFoFrGsr182wgOJoRmSwIDAQABAoICACmeL5fBhsI8b9HRjr1K1rmU\nR9AMGSa3tnAUw7syZ6eCsDV7i3wAwkWJThU+vS1jaoljdAAXEDfT9XNJ2w7YuE06\nrVtG8Ofhl29szoaA4euJS7K9SEFcVfa8NaeDA1W1SQEekG2/kAckYCbaUmm6og0F\ndpDLLPfcZGZXM0u1JXEUh7+Ub5mJSZQrBCZxIlMUYvjGNJ+Pog0ADLjaPCBblU2K\nz4zfx61OsjyIVgw4V2RDS1zuh41lAUgk91b7blV9LffRbVJGjhm5f35hnKypAsJJ\nZdkYvplFxcISuGyMVCtDUBDpmXdV6szlTX4rp7JJ144kX3rOLWqWTh/3n2jT4lKb\nR9nkQ6ldi5h5PMSSWemYij4uj+L+xT+KIh2OQce3pfnwTblsbCWVNd/6tN02chQl\nu4XjRUvbqLi1NbKKDa/dP5PF78jkoRnp+IppZ9yxhFKg8MZmHHJ4FO3wZ8sPHhuo\nV2pyX95iNbvjW3nUDciekfeDblhVOlpCcnhqenBImbmNsLrQgSslXUXrdeNAlCIe\nXp9MErTnHpSQAUquA0IcRSMuJl97N/USJ2ALomWfWlYoNfS/2OhF+6k3UTlimYID\nEsSBytkCIBJSDb+fy7hB11IRQqdTSOrhi7BtsQpf7j+W7ELvNwhHFOD4oYqxF27v\noFclVMcpYB/eX2ujXvP1AoIBAQD6yMZiRp1FpPMwPDEOKouZylH/tN7DGPAPSQ2k\nqjF6XU0e8ivxwEJMUTDG3+gyvl6fH1qdVUP+aMQp+7KldF9kxki/NXIO4d6UIUD+\nu7H5/Qz6UAdHHWnZcplODKT2XbGEq7HROjgDIjhX1takJ+P+DZatG6NzCoymhiq9\nWv252hJh+ZOnvuXLE1tNH5cGlPKXVdUZ595Oc7BvMZ79X8aT7usgx8WuJueht95s\nkexrTe3S+bLSIy5AThQEqQSPI2bht5g2P8JcvKdz0Dpq8lrb2QvSkmPmKHApuyqE\nIz0eCQb2Ywo+yt8iyE52F2+xMAHR2+sfZdLEtIlRvjUV45R9AoIBAQDHb9m8wVta\nGPWb21lbSV1JelBFFrznclbfTygSgm00nfKcJWzOus4rQ90CRSHi6osjcBzM9d+T\nmut8DT6sVppqw1pcGcRObf3xQjQu10vIVCfZMonEDIxG3RJlp5lX5Qd0x8FGW0+5\nfF3s9xAhw45HpmDLb4GPlJC4pivJq3F9t0zeE4GBXjQG8i6zmyZgOFucp6lYHsSY\nSFR8NnLFH0AESBVVxmlQLmh1WyPvoT5xtN+wAb+NL43XpP11PSmyiZ1t6olpB3Gd\njGmDuv8zT/L/Eu45Ho5niHZvlUTRDQhUseFhnpNqJgqFdcorQyIAdHiQqKugtaSX\nC8esU3c4WshnAoIBADQsBKl5S0qr0DPesc3ip/wsjPaHaDhqPbbQWdhB190+/8ZK\nVz4J40EBOwaEmkfENucfnLhSfry0iuq5BCdLmHTck1HECqBx+N4UNPNJlPMO495H\nO9xdkCG+p4oHM2JVh5K0LV/7np94RQRxG2I3MkUuCoSk1VIfhbc2/jk6bsJ1TZG4\nXDFvk1q2Ai5/PeoOnpFBN/4VsLfddX0Mc6j+fc9UyvGc3dEnItUP7WPkz6xbH/je\nHYd97idOlveJOfuVP9gBW9cdWI/2Z1e+oAiTtrc55i2+aq39B6iG2Yd31UUkV6B2\nZjE9/0G7Lid/JKtV82r3N2jmw/xMGq04xs5w8/kCggEBAKNW5SKlzhbFeGrUxKNy\nO7gROCrNi5uXVrUAFJbMQXqlnezq7emGr5JZu2m/ixhY9enpSX1IJnuylwj7pAfr\nyf6Ezr290LxXc3MjwK9YX1XMLvLBZHmvuTfUmdut33ZQOsIXVCE2ad5FkHuigZDV\no/LkvkP/qEIa8Eh6uEQsaQAInykHGrsEl2HU+hDZkh2eKtHrs1Nbp7H9E0zEH014\n4apgCzE8Fka4K49qPM1m50ijVczGMccFWotyMq/RjxQNh2VdgHsHwLLDLCvafGbf\nJOpp67fWYdVDu5R50WnR3a/YG/oisSNv0pApv5GdIvzyZ0g7DI3MFugqmrd1iKAc\nIiMCggEBAOqlCaNS5qU39gKQqmLsCF5ByXgJEt5SnnBM0ctvuaZpMYNR4C+spRxj\nXvOJkBpTP9msuVLGNaxf8XxyMIj4gnYWRclxketKEusQN08zlqOwKs+idp+Y+5Vf\n5IVXlEH9h2yM4ZvTY4oiY9OT0dAjERqsydbH7yvOe2hX4nKY4E8c/J7Adda/plzG\n+dDOJeOGwnyFKXQ+X1efJo9GIOmsun9twIN77nz0j7MJoWDi0S6zccQtlsNhnXnP\ng3xeaEI7WAuOHyizGuD4vwJVYq7jEPXCG07pUX9O+IT8S4Dk8LJnqjN2fmsYa93Z\nVNZv2hCnQdKiJHAUT0UIVpzbI3qiKW0=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "examples/data/tls/server2.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFQjCCAyqgAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwKTEOMAwGA1UECgwFVG9u\naWMxFzAVBgNVBAMMDnRlc3Qtc2VydmVyX2NhMB4XDTI2MDIxODE5MTI0MVoXDTM2\nMDIxNjE5MTI0MVowJjEOMAwGA1UECgwFVG9uaWMxFDASBgNVBAMMC3Rlc3Qtc2Vy\ndmVyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw1+kkYKGuI08b427\nMfPhFzl3tCeYHW3adZ7Ax+rarC03CwHS78RC+Uo2v1Rn5v+kG4GIohX+BH70jYQG\n3v9oINeMlU8aGaBk8q6pz3yQnehiur+NjKZhtAf3MWLFmWnPnWjyNPCoGBDuTKQR\n71m2Qj6KnhUaH1O0waw/Bi28gQWUouBqwphQH+sHHTnXWYuvvWuCttjxequUFRGm\nP8EF4SPhAQFlA3HzIZ0nR6RzyzNiQ/AztdEfoCxLOCLKvMZwHXm8WQH6aYZREVJY\naOvPGXbksgfl2eIcSrcukqiNe/qrekb0XRs0wzjvjQIwWtXUhYgxyhmVtjkrv72u\nKw/M7X9obNoQoPvjBlOei/H+Pxm1g50166XaqAuD/LFgbDVX7+wVay+duztl4ARV\nybwo+XQR8IxzTOJCs0mMWniXA+Bz72Zf9eNw7w1n3aCOFnnIobWsWHO/rdTSv0iI\n/BQPhTBDUa1s2nMGNrbHOuM3Qa88krRnTxGK3rWCmEjbxvQMrQk+4yPsgmZE79XC\n4rVgODdu0otnr9XPBSjVlYLBCvf1kE6ufMYCNnviJxlzU2Ju+cBqLT7nyv2f93Id\nIfCRPNZ27gWNd++POXClSS2nrwbEn3XLtiooUTsBh0LOAIkV8bn9YJYsDQXnaoHX\nUyEEbeXrhaBaxrK9fNsIDiaEZksCAwEAAaN3MHUwDAYDVR0TAQH/BAIwADAdBgNV\nHQ4EFgQUzCR56MKIPquyXh10IpIV3blZbNAwDgYDVR0PAQH/BAQDAgOoMBUGA1Ud\nEQQOMAyCCioudGVzdC5jb20wHwYDVR0jBBgwFoAUnNE1vPdm/LoFwKWoQxpK0XYy\nI+0wDQYJKoZIhvcNAQELBQADggIBAHi30l7AChiw6bhZkUOYmsnvyWOeuT7ghqwY\n2IWizi4J1txRVlBcoG5Vrltaoe4mv5RDC90phKU/C3a0IxQYRVHJbIhGe++5ngAh\nAOOJzBta74nDzaQ/3e03Dr741F6LIsnlQj396X5fwqvhno5uhTeL/xtrgCPg8uck\n5Pl4d1HXXE8YtzAvmkWrhE5Uc9DgO5z0pN96zugLheLB8jNKfdGrnfKCdOzb0mqO\nmPM3ThWQWqKAYEVsiRUNWfANfUJOppNV7Uj6WkHMxMeZAWVwTeEiU1ay7dCiiZMd\nsVx/VlE91p002Jhq1xGuB9W9+6ra7XJdp9aQaa1qnEMKk/apTV+u33UAgETs/SqU\nZvOIoV3xR4YBbCraE8sIjZJSpPYz7nSCoosYhSVd5BhymhQsMlVPq4mVFhX+oSGt\neO2nk/mKGD3Yd5H0F8K5FzqaX51PCX4sgTxoQLH2WDAhifTv5vncbTCNLnky78OF\nqW9qaBRTLnpgqtp5SYTsbGgUbSZEhNDmy2ONvmd6SVAEcrEJ8ahSUDTC98vHX6Wd\nSVVNTcWDFlqTr2qzDtXBzhtKJlGeuS/OH9H+dSoQ0h2zDpiH3FJTvbd8Y2S2QUID\n/NiTE6LvXSVyWY03Cq2nRtt1zcUIiIOCO9PeEOx23+zmfBZ17afAwDGLv2LAsYAX\nB/6jITez\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/helloworld-tutorial.md",
    "content": "# Getting Started\n\nThis tutorial is meant to be an introduction to Tonic and assumes that you have basic [Rust] experience as well as an understanding of what [protocol buffers] are. If you don't, feel free to read up on the pages linked in this paragraph and come back to this tutorial once you feel you are ready!\n\n[rust]: https://www.rust-lang.org/\n[protocol buffers]: https://developers.google.com/protocol-buffers/docs/overview\n\n## Prerequisites\n\nTo run the sample code and walk through the tutorial, the only prerequisite is Rust itself.\n[rustup] is a convenient tool to install it, if you haven't already.\n\n[rustup]: https://rustup.rs\n\n## Project Setup\n\nFor this tutorial, we will start by creating a new Rust project with Cargo:\n\n```shell\n$ cargo new helloworld-tonic\n$ cd helloworld-tonic\n```\n\n`tonic` works on rust `1.39` and above as it requires support for the `async_await`\nfeature.\n\n```bash\n$ rustup update\n```\n\n## Defining the HelloWorld service\n\nOur first step is to define the gRPC _service_ and the method _request_ and _response_ types using\n[protocol buffers]. We will keep our `.proto` files in a directory in our project's root.\nNote that Tonic does not really care where our `.proto` definitions live.\n\n```shell\n$ mkdir proto\n$ touch proto/helloworld.proto\n```\n\nThen you define RPC methods inside your service definition, specifying their request and response\ntypes. gRPC lets you define four kinds of service methods, all of which are supported by Tonic. For this tutorial we will only use a simple RPC, if you would like to see a Tonic example which uses all four kinds please read the [routeguide tutorial].\n\n[routeguide tutorial]: https://github.com/hyperium/tonic/blob/master/examples/routeguide-tutorial.md\n\nFirst we define our package name, which is what Tonic looks for when including your protos in the client and server applications. Lets give this one a name of `helloworld`.\n\n```proto\nsyntax = \"proto3\";\npackage helloworld;\n```\n\nNext we need to define our service. This service will contain the actual RPC calls we will be using in our application. An RPC contains an Identifier, a Request type, and returns a Response type. Here is our Greeter service, which provides the SayHello RPC method.\n\n```proto\nservice Greeter {\n    // Our SayHello rpc accepts HelloRequests and returns HelloReplies\n    rpc SayHello (HelloRequest) returns (HelloReply);\n}\n```\n\nFinally, we have to actually define those types we used above in our `SayHello` RPC method. RPC types are defined as messages which contain typed fields. Here is what that will look like for our HelloWorld application:\n\n```proto\nmessage HelloRequest {\n    // Request message contains the name to be greeted\n    string name = 1;\n}\n\nmessage HelloReply {\n    // Reply contains the greeting message\n    string message = 1;\n}\n```\n\nGreat! Now our `.proto` file should be complete and ready for use in our application. Here is what it should look like completed:\n\n```proto\nsyntax = \"proto3\";\npackage helloworld;\n\nservice Greeter {\n    rpc SayHello (HelloRequest) returns (HelloReply);\n}\n\nmessage HelloRequest {\n   string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n```\n\n## Application Setup\n\nNow that have defined the protobuf for our application we can start writing our application with Tonic! Let's first add our required dependencies to the `Cargo.toml`.\n\n```toml\n[package]\nname = \"helloworld-tonic\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[[bin]] # Bin to run the HelloWorld gRPC server\nname = \"helloworld-server\"\npath = \"src/server.rs\"\n\n[[bin]] # Bin to run the HelloWorld gRPC client\nname = \"helloworld-client\"\npath = \"src/client.rs\"\n\n[dependencies]\ntonic = \"*\"\nprost = \"0.14\"\ntonic-prost = \"*\"\ntokio = { version = \"1.0\", features = [\"macros\", \"rt-multi-thread\"] }\n\n[build-dependencies]\ntonic-prost-build = \"*\"\n```\n\nWe include `tonic-build` as a useful way to incorporate the generation of our client and server gRPC code into the build process of our application. We will setup this build process now:\n\n## Generating Server and Client code\n\nAt the root of your project (not /src), create a `build.rs` file and add the following code:\n\n```rust\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    tonic_prost_build::compile_protos(\"proto/helloworld.proto\")?;\n    Ok(())\n}\n```\n\nThis tells `tonic-build` to compile your protobufs when you build your Rust project. While you can configure this build process in a number of ways, we will not get into the details in this introductory tutorial. Please see the [tonic-build] documentation for details on configuration.\n\n[tonic-build]: https://github.com/hyperium/tonic/blob/master/tonic-build/README.md\n\n## Writing our Server\n\nNow that the build process is written and our dependencies are all setup, we can begin writing the fun stuff! We need to import the things we will be using in our server, including the protobuf. Start by making a file called `server.rs` in your `/src` directory and writing the following code:\n\n```rust\nuse tonic::{transport::Server, Request, Response, Status};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\"); // The string specified here must match the proto package name\n}\n```\n\nNext up, let's implement the Greeter service we previously defined in our `.proto` file. Here's what that might look like:\n\n```rust\n#[derive(Debug, Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>, // Accept request of type HelloRequest\n    ) -> Result<Response<HelloReply>, Status> { // Return an instance of type HelloReply\n        println!(\"Got a request: {:?}\", request);\n\n        let reply = HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name), // We must use .into_inner() as the fields of gRPC requests and responses are private\n        };\n\n        Ok(Response::new(reply)) // Send back our formatted greeting\n    }\n}\n```\n\nFinally, let's define the Tokio runtime that our server will actually run on. This requires Tokio to be added as a dependency, so make sure you included that!\n\n```rust\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse()?;\n    let greeter = MyGreeter::default();\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n```\n\nAltogether your server should look something like this once you are done:\n\n```rust\nuse tonic::{transport::Server, Request, Response, Status};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Debug, Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request: {:?}\", request);\n\n        let reply = HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse()?;\n    let greeter = MyGreeter::default();\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n```\n\nYou should now be able to run your HelloWorld gRPC server using the command `cargo run --bin helloworld-server`. This uses the [[bin]] we defined earlier in our `Cargo.toml` to run specifically the server. \n\nIf you have a gRPC GUI client such as [Postman] you should be able to send requests to the server and get back greetings!\n\nOr if you use [grpcurl] then you can simply try send requests like this:\n```\n$ grpcurl -plaintext -import-path ./proto -proto helloworld.proto -d '{\"name\": \"Tonic\"}' '[::1]:50051' helloworld.Greeter/SayHello\n```\nAnd receiving responses like this:\n```\n{\n  \"message\": \"Hello Tonic!\"\n}\n```\n\n[postman]: https://www.postman.com/\n[grpcurl]: https://github.com/fullstorydev/grpcurl\n\n## Writing our Client\n\nSo now we have a running gRPC server, and that's great but how can our application communicate with it? This is where our client would come in. Tonic supports both client and server implementations. Similar to the server, we will start by creating a file `client.rs` in our `/src` directory and importing everything we will need:\n\n```rust\nuse hello_world::greeter_client::GreeterClient;\nuse hello_world::HelloRequest;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n```\n\nThe client is much simpler than the server as we don't need to implement any service methods, just make requests. Here is a Tokio runtime which will make our request and print the response to your terminal:\n\n```rust\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={:?}\", response);\n\n    Ok(())\n}\n```\n\nThat's it! Our complete client file should look something like below, if it doesn't please go back and make sure you followed along correctly:\n\n```rust\nuse hello_world::greeter_client::GreeterClient;\nuse hello_world::HelloRequest;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={:?}\", response);\n\n    Ok(())\n}\n```\n\n## Putting it all together\n\nAt this point we have written our protobuf file, a build file to compile our protobufs, a server which implements our SayHello service, and a client which makes requests to our server. You should have a `proto/helloworld.proto` file, a `build.rs` file at the root of your project, and `src/server.rs` as well as a `src/client.rs` files.\n\nTo run the server, run `cargo run --bin helloworld-server`.\nTo run the client, run `cargo run --bin helloworld-client` in another terminal window.\n\nYou should see the request logged out by the server in its terminal window, as well as the response logged out by the client in its window.\n\nCongrats on making it through this introductory tutorial! We hope that this walkthrough tutorial has helped you understand the basics of Tonic, and how to get started writing high-performance, interoperable, and flexible gRPC servers in Rust. For a more in-depth tutorial which showcases an advanced gRPC server in Tonic, please see the [routeguide tutorial].\n"
  },
  {
    "path": "examples/proto/attrs/attrs.proto",
    "content": "syntax = \"proto3\";\n\npackage attrs;\n\n// EchoRequest is the request for echo.\nmessage EchoRequest {\n  string message = 1;\n}\n\n// EchoResponse is the response for echo.\nmessage EchoResponse {\n  string message = 1;\n}\n\n// Echo is the echo service.\nservice Echo {\n  // UnaryEcho is unary echo.\n  rpc UnaryEcho(EchoRequest) returns (EchoResponse) {}\n}\n"
  },
  {
    "path": "examples/proto/echo/echo.proto",
    "content": "/*\n *\n * Copyright 2018 gRPC authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n syntax = \"proto3\";\n\n package grpc.examples.echo;\n\n // EchoRequest is the request for echo.\n message EchoRequest {\n   string message = 1;\n }\n\n // EchoResponse is the response for echo.\n message EchoResponse {\n   string message = 1;\n }\n\n // Echo is the echo service.\n service Echo {\n   // UnaryEcho is unary echo.\n   rpc UnaryEcho(EchoRequest) returns (EchoResponse) {}\n   // ServerStreamingEcho is server side streaming.\n   rpc ServerStreamingEcho(EchoRequest) returns (stream EchoResponse) {}\n   // ClientStreamingEcho is client side streaming.\n   rpc ClientStreamingEcho(stream EchoRequest) returns (EchoResponse) {}\n   // BidirectionalStreamingEcho is bidi streaming.\n   rpc BidirectionalStreamingEcho(stream EchoRequest) returns (stream EchoResponse) {}\n }\n"
  },
  {
    "path": "examples/proto/googleapis/google/api/annotations.proto",
    "content": "// Copyright (c) 2015, Google Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\nimport \"google/api/http.proto\";\nimport \"google/protobuf/descriptor.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"AnnotationsProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\nextend google.protobuf.MethodOptions {\n  // See `HttpRule`.\n  HttpRule http = 72295728;\n}\n"
  },
  {
    "path": "examples/proto/googleapis/google/api/client.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\nimport \"google/protobuf/descriptor.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"ClientProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\nextend google.protobuf.MethodOptions {\n  // A definition of a client library method signature.\n  //\n  // In client libraries, each proto RPC corresponds to one or more methods\n  // which the end user is able to call, and calls the underlying RPC.\n  // Normally, this method receives a single argument (a struct or instance\n  // corresponding to the RPC request object). Defining this field will\n  // add one or more overloads providing flattened or simpler method signatures\n  // in some languages.\n  //\n  // The fields on the method signature are provided as a comma-separated\n  // string.\n  //\n  // For example, the proto RPC and annotation:\n  //\n  //   rpc CreateSubscription(CreateSubscriptionRequest)\n  //       returns (Subscription) {\n  //     option (google.api.method_signature) = \"name,topic\";\n  //   }\n  //\n  // Would add the following Java overload (in addition to the method accepting\n  // the request object):\n  //\n  //   public final Subscription createSubscription(String name, String topic)\n  //\n  // The following backwards-compatibility guidelines apply:\n  //\n  //   * Adding this annotation to an unannotated method is backwards\n  //     compatible.\n  //   * Adding this annotation to a method which already has existing\n  //     method signature annotations is backwards compatible if and only if\n  //     the new method signature annotation is last in the sequence.\n  //   * Modifying or removing an existing method signature annotation is\n  //     a breaking change.\n  //   * Re-ordering existing method signature annotations is a breaking\n  //     change.\n  repeated string method_signature = 1051;\n}\n\nextend google.protobuf.ServiceOptions {\n  // The hostname for this service.\n  // This should be specified with no prefix or protocol.\n  //\n  // Example:\n  //\n  //   service Foo {\n  //     option (google.api.default_host) = \"foo.googleapi.com\";\n  //     ...\n  //   }\n  string default_host = 1049;\n\n  // OAuth scopes needed for the client.\n  //\n  // Example:\n  //\n  //   service Foo {\n  //     option (google.api.oauth_scopes) = \\\n  //       \"https://www.googleapis.com/auth/cloud-platform\";\n  //     ...\n  //   }\n  //\n  // If there is more than one scope, use a comma-separated string:\n  //\n  // Example:\n  //\n  //   service Foo {\n  //     option (google.api.oauth_scopes) = \\\n  //       \"https://www.googleapis.com/auth/cloud-platform,\"\n  //       \"https://www.googleapis.com/auth/monitoring\";\n  //     ...\n  //   }\n  string oauth_scopes = 1050;\n}\n"
  },
  {
    "path": "examples/proto/googleapis/google/api/field_behavior.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\nimport \"google/protobuf/descriptor.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"FieldBehaviorProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\nextend google.protobuf.FieldOptions {\n  // A designation of a specific field behavior (required, output only, etc.)\n  // in protobuf messages.\n  //\n  // Examples:\n  //\n  //   string name = 1 [(google.api.field_behavior) = REQUIRED];\n  //   State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY];\n  //   google.protobuf.Duration ttl = 1\n  //     [(google.api.field_behavior) = INPUT_ONLY];\n  //   google.protobuf.Timestamp expire_time = 1\n  //     [(google.api.field_behavior) = OUTPUT_ONLY,\n  //      (google.api.field_behavior) = IMMUTABLE];\n  repeated google.api.FieldBehavior field_behavior = 1052;\n}\n\n// An indicator of the behavior of a given field (for example, that a field\n// is required in requests, or given as output but ignored as input).\n// This **does not** change the behavior in protocol buffers itself; it only\n// denotes the behavior and may affect how API tooling handles the field.\n//\n// Note: This enum **may** receive new values in the future.\nenum FieldBehavior {\n  // Conventional default for enums. Do not use this.\n  FIELD_BEHAVIOR_UNSPECIFIED = 0;\n\n  // Specifically denotes a field as optional.\n  // While all fields in protocol buffers are optional, this may be specified\n  // for emphasis if appropriate.\n  OPTIONAL = 1;\n\n  // Denotes a field as required.\n  // This indicates that the field **must** be provided as part of the request,\n  // and failure to do so will cause an error (usually `INVALID_ARGUMENT`).\n  REQUIRED = 2;\n\n  // Denotes a field as output only.\n  // This indicates that the field is provided in responses, but including the\n  // field in a request does nothing (the server *must* ignore it and\n  // *must not* throw an error as a result of the field's presence).\n  OUTPUT_ONLY = 3;\n\n  // Denotes a field as input only.\n  // This indicates that the field is provided in requests, and the\n  // corresponding field is not included in output.\n  INPUT_ONLY = 4;\n\n  // Denotes a field as immutable.\n  // This indicates that the field may be set once in a request to create a\n  // resource, but may not be changed thereafter.\n  IMMUTABLE = 5;\n\n  // Denotes that a (repeated) field is an unordered list.\n  // This indicates that the service may provide the elements of the list\n  // in any arbitrary order, rather than the order the user originally\n  // provided. Additionally, the list's order may or may not be stable.\n  UNORDERED_LIST = 6;\n}\n"
  },
  {
    "path": "examples/proto/googleapis/google/api/http.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"HttpProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\n// Defines the HTTP configuration for an API service. It contains a list of\n// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method\n// to one or more HTTP REST API methods.\nmessage Http {\n  // A list of HTTP configuration rules that apply to individual API methods.\n  //\n  // **NOTE:** All service configuration rules follow \"last one wins\" order.\n  repeated HttpRule rules = 1;\n\n  // When set to true, URL path parameters will be fully URI-decoded except in\n  // cases of single segment matches in reserved expansion, where \"%2F\" will be\n  // left encoded.\n  //\n  // The default behavior is to not decode RFC 6570 reserved characters in multi\n  // segment matches.\n  bool fully_decode_reserved_expansion = 2;\n}\n\n// # gRPC Transcoding\n//\n// gRPC Transcoding is a feature for mapping between a gRPC method and one or\n// more HTTP REST endpoints. It allows developers to build a single API service\n// that supports both gRPC APIs and REST APIs. Many systems, including [Google\n// APIs](https://github.com/googleapis/googleapis),\n// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC\n// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),\n// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature\n// and use it for large scale production services.\n//\n// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies\n// how different portions of the gRPC request message are mapped to the URL\n// path, URL query parameters, and HTTP request body. It also controls how the\n// gRPC response message is mapped to the HTTP response body. `HttpRule` is\n// typically specified as an `google.api.http` annotation on the gRPC method.\n//\n// Each mapping specifies a URL path template and an HTTP method. The path\n// template may refer to one or more fields in the gRPC request message, as long\n// as each field is a non-repeated field with a primitive (non-message) type.\n// The path template controls how fields of the request message are mapped to\n// the URL path.\n//\n// Example:\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//             get: \"/v1/{name=messages/*}\"\n//         };\n//       }\n//     }\n//     message GetMessageRequest {\n//       string name = 1; // Mapped to URL path.\n//     }\n//     message Message {\n//       string text = 1; // The resource content.\n//     }\n//\n// This enables an HTTP REST to gRPC mapping as below:\n//\n// HTTP | gRPC\n// -----|-----\n// `GET /v1/messages/123456`  | `GetMessage(name: \"messages/123456\")`\n//\n// Any fields in the request message which are not bound by the path template\n// automatically become HTTP query parameters if there is no HTTP request body.\n// For example:\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//             get:\"/v1/messages/{message_id}\"\n//         };\n//       }\n//     }\n//     message GetMessageRequest {\n//       message SubMessage {\n//         string subfield = 1;\n//       }\n//       string message_id = 1; // Mapped to URL path.\n//       int64 revision = 2;    // Mapped to URL query parameter `revision`.\n//       SubMessage sub = 3;    // Mapped to URL query parameter `sub.subfield`.\n//     }\n//\n// This enables a HTTP JSON to RPC mapping as below:\n//\n// HTTP | gRPC\n// -----|-----\n// `GET /v1/messages/123456?revision=2&sub.subfield=foo` |\n// `GetMessage(message_id: \"123456\" revision: 2 sub: SubMessage(subfield:\n// \"foo\"))`\n//\n// Note that fields which are mapped to URL query parameters must have a\n// primitive type or a repeated primitive type or a non-repeated message type.\n// In the case of a repeated type, the parameter can be repeated in the URL\n// as `...?param=A&param=B`. In the case of a message type, each field of the\n// message is mapped to a separate parameter, such as\n// `...?foo.a=A&foo.b=B&foo.c=C`.\n//\n// For HTTP methods that allow a request body, the `body` field\n// specifies the mapping. Consider a REST update method on the\n// message resource collection:\n//\n//     service Messaging {\n//       rpc UpdateMessage(UpdateMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//           patch: \"/v1/messages/{message_id}\"\n//           body: \"message\"\n//         };\n//       }\n//     }\n//     message UpdateMessageRequest {\n//       string message_id = 1; // mapped to the URL\n//       Message message = 2;   // mapped to the body\n//     }\n//\n// The following HTTP JSON to RPC mapping is enabled, where the\n// representation of the JSON in the request body is determined by\n// protos JSON encoding:\n//\n// HTTP | gRPC\n// -----|-----\n// `PATCH /v1/messages/123456 { \"text\": \"Hi!\" }` | `UpdateMessage(message_id:\n// \"123456\" message { text: \"Hi!\" })`\n//\n// The special name `*` can be used in the body mapping to define that\n// every field not bound by the path template should be mapped to the\n// request body.  This enables the following alternative definition of\n// the update method:\n//\n//     service Messaging {\n//       rpc UpdateMessage(Message) returns (Message) {\n//         option (google.api.http) = {\n//           patch: \"/v1/messages/{message_id}\"\n//           body: \"*\"\n//         };\n//       }\n//     }\n//     message Message {\n//       string message_id = 1;\n//       string text = 2;\n//     }\n//\n//\n// The following HTTP JSON to RPC mapping is enabled:\n//\n// HTTP | gRPC\n// -----|-----\n// `PATCH /v1/messages/123456 { \"text\": \"Hi!\" }` | `UpdateMessage(message_id:\n// \"123456\" text: \"Hi!\")`\n//\n// Note that when using `*` in the body mapping, it is not possible to\n// have HTTP parameters, as all fields not bound by the path end in\n// the body. This makes this option more rarely used in practice when\n// defining REST APIs. The common usage of `*` is in custom methods\n// which don't use the URL at all for transferring data.\n//\n// It is possible to define multiple HTTP methods for one RPC by using\n// the `additional_bindings` option. Example:\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//           get: \"/v1/messages/{message_id}\"\n//           additional_bindings {\n//             get: \"/v1/users/{user_id}/messages/{message_id}\"\n//           }\n//         };\n//       }\n//     }\n//     message GetMessageRequest {\n//       string message_id = 1;\n//       string user_id = 2;\n//     }\n//\n// This enables the following two alternative HTTP JSON to RPC mappings:\n//\n// HTTP | gRPC\n// -----|-----\n// `GET /v1/messages/123456` | `GetMessage(message_id: \"123456\")`\n// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: \"me\" message_id:\n// \"123456\")`\n//\n// ## Rules for HTTP mapping\n//\n// 1. Leaf request fields (recursive expansion nested messages in the request\n//    message) are classified into three categories:\n//    - Fields referred by the path template. They are passed via the URL path.\n//    - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP\n//      request body.\n//    - All other fields are passed via the URL query parameters, and the\n//      parameter name is the field path in the request message. A repeated\n//      field can be represented as multiple query parameters under the same\n//      name.\n//  2. If [HttpRule.body][google.api.HttpRule.body] is \"*\", there is no URL query parameter, all fields\n//     are passed via URL path and HTTP request body.\n//  3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all\n//     fields are passed via URL path and URL query parameters.\n//\n// ### Path template syntax\n//\n//     Template = \"/\" Segments [ Verb ] ;\n//     Segments = Segment { \"/\" Segment } ;\n//     Segment  = \"*\" | \"**\" | LITERAL | Variable ;\n//     Variable = \"{\" FieldPath [ \"=\" Segments ] \"}\" ;\n//     FieldPath = IDENT { \".\" IDENT } ;\n//     Verb     = \":\" LITERAL ;\n//\n// The syntax `*` matches a single URL path segment. The syntax `**` matches\n// zero or more URL path segments, which must be the last part of the URL path\n// except the `Verb`.\n//\n// The syntax `Variable` matches part of the URL path as specified by its\n// template. A variable template must not contain other variables. If a variable\n// matches a single path segment, its template may be omitted, e.g. `{var}`\n// is equivalent to `{var=*}`.\n//\n// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`\n// contains any reserved character, such characters should be percent-encoded\n// before the matching.\n//\n// If a variable contains exactly one path segment, such as `\"{var}\"` or\n// `\"{var=*}\"`, when such a variable is expanded into a URL path on the client\n// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The\n// server side does the reverse decoding. Such variables show up in the\n// [Discovery\n// Document](https://developers.google.com/discovery/v1/reference/apis) as\n// `{var}`.\n//\n// If a variable contains multiple path segments, such as `\"{var=foo/*}\"`\n// or `\"{var=**}\"`, when such a variable is expanded into a URL path on the\n// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.\n// The server side does the reverse decoding, except \"%2F\" and \"%2f\" are left\n// unchanged. Such variables show up in the\n// [Discovery\n// Document](https://developers.google.com/discovery/v1/reference/apis) as\n// `{+var}`.\n//\n// ## Using gRPC API Service Configuration\n//\n// gRPC API Service Configuration (service config) is a configuration language\n// for configuring a gRPC service to become a user-facing product. The\n// service config is simply the YAML representation of the `google.api.Service`\n// proto message.\n//\n// As an alternative to annotating your proto file, you can configure gRPC\n// transcoding in your service config YAML files. You do this by specifying a\n// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same\n// effect as the proto annotation. This can be particularly useful if you\n// have a proto that is reused in multiple services. Note that any transcoding\n// specified in the service config will override any matching transcoding\n// configuration in the proto.\n//\n// Example:\n//\n//     http:\n//       rules:\n//         # Selects a gRPC method and applies HttpRule to it.\n//         - selector: example.v1.Messaging.GetMessage\n//           get: /v1/messages/{message_id}/{sub.subfield}\n//\n// ## Special notes\n//\n// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the\n// proto to JSON conversion must follow the [proto3\n// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).\n//\n// While the single segment variable follows the semantics of\n// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String\n// Expansion, the multi segment variable **does not** follow RFC 6570 Section\n// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion\n// does not expand special characters like `?` and `#`, which would lead\n// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding\n// for multi segment variables.\n//\n// The path variables **must not** refer to any repeated or mapped field,\n// because client libraries are not capable of handling such variable expansion.\n//\n// The path variables **must not** capture the leading \"/\" character. The reason\n// is that the most common use case \"{var}\" does not capture the leading \"/\"\n// character. For consistency, all path variables must share the same behavior.\n//\n// Repeated message fields must not be mapped to URL query parameters, because\n// no client library can support such complicated mapping.\n//\n// If an API needs to use a JSON array for request or response body, it can map\n// the request or response body to a repeated field. However, some gRPC\n// Transcoding implementations may not support this feature.\nmessage HttpRule {\n  // Selects a method to which this rule applies.\n  //\n  // Refer to [selector][google.api.DocumentationRule.selector] for syntax details.\n  string selector = 1;\n\n  // Determines the URL pattern is matched by this rules. This pattern can be\n  // used with any of the {get|put|post|delete|patch} methods. A custom method\n  // can be defined using the 'custom' field.\n  oneof pattern {\n    // Maps to HTTP GET. Used for listing and getting information about\n    // resources.\n    string get = 2;\n\n    // Maps to HTTP PUT. Used for replacing a resource.\n    string put = 3;\n\n    // Maps to HTTP POST. Used for creating a resource or performing an action.\n    string post = 4;\n\n    // Maps to HTTP DELETE. Used for deleting a resource.\n    string delete = 5;\n\n    // Maps to HTTP PATCH. Used for updating a resource.\n    string patch = 6;\n\n    // The custom pattern is used for specifying an HTTP method that is not\n    // included in the `pattern` field, such as HEAD, or \"*\" to leave the\n    // HTTP method unspecified for this rule. The wild-card rule is useful\n    // for services that provide content to Web (HTML) clients.\n    CustomHttpPattern custom = 8;\n  }\n\n  // The name of the request field whose value is mapped to the HTTP request\n  // body, or `*` for mapping all request fields not captured by the path\n  // pattern to the HTTP body, or omitted for not having any HTTP request body.\n  //\n  // NOTE: the referred field must be present at the top-level of the request\n  // message type.\n  string body = 7;\n\n  // Optional. The name of the response field whose value is mapped to the HTTP\n  // response body. When omitted, the entire response message will be used\n  // as the HTTP response body.\n  //\n  // NOTE: The referred field must be present at the top-level of the response\n  // message type.\n  string response_body = 12;\n\n  // Additional HTTP bindings for the selector. Nested bindings must\n  // not contain an `additional_bindings` field themselves (that is,\n  // the nesting may only be one level deep).\n  repeated HttpRule additional_bindings = 11;\n}\n\n// A custom pattern is used for defining custom HTTP verb.\nmessage CustomHttpPattern {\n  // The name of this custom HTTP verb.\n  string kind = 1;\n\n  // The path matched by this custom verb.\n  string path = 2;\n}\n"
  },
  {
    "path": "examples/proto/googleapis/google/api/resource.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\nimport \"google/protobuf/descriptor.proto\";\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"ResourceProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\nextend google.protobuf.FieldOptions {\n  // An annotation that describes a resource reference, see\n  // [ResourceReference][].\n  google.api.ResourceReference resource_reference = 1055;\n}\n\nextend google.protobuf.FileOptions {\n  // An annotation that describes a resource definition without a corresponding\n  // message; see [ResourceDescriptor][].\n  repeated google.api.ResourceDescriptor resource_definition = 1053;\n}\n\nextend google.protobuf.MessageOptions {\n  // An annotation that describes a resource definition, see\n  // [ResourceDescriptor][].\n  google.api.ResourceDescriptor resource = 1053;\n}\n\n// A simple descriptor of a resource type.\n//\n// ResourceDescriptor annotates a resource message (either by means of a\n// protobuf annotation or use in the service config), and associates the\n// resource's schema, the resource type, and the pattern of the resource name.\n//\n// Example:\n//\n//     message Topic {\n//       // Indicates this message defines a resource schema.\n//       // Declares the resource type in the format of {service}/{kind}.\n//       // For Kubernetes resources, the format is {api group}/{kind}.\n//       option (google.api.resource) = {\n//         type: \"pubsub.googleapis.com/Topic\"\n//         name_descriptor: {\n//           pattern: \"projects/{project}/topics/{topic}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Project\"\n//           parent_name_extractor: \"projects/{project}\"\n//         }\n//       };\n//     }\n//\n// The ResourceDescriptor Yaml config will look like:\n//\n//     resources:\n//     - type: \"pubsub.googleapis.com/Topic\"\n//       name_descriptor:\n//         - pattern: \"projects/{project}/topics/{topic}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Project\"\n//           parent_name_extractor: \"projects/{project}\"\n//\n// Sometimes, resources have multiple patterns, typically because they can\n// live under multiple parents.\n//\n// Example:\n//\n//     message LogEntry {\n//       option (google.api.resource) = {\n//         type: \"logging.googleapis.com/LogEntry\"\n//         name_descriptor: {\n//           pattern: \"projects/{project}/logs/{log}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Project\"\n//           parent_name_extractor: \"projects/{project}\"\n//         }\n//         name_descriptor: {\n//           pattern: \"folders/{folder}/logs/{log}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Folder\"\n//           parent_name_extractor: \"folders/{folder}\"\n//         }\n//         name_descriptor: {\n//           pattern: \"organizations/{organization}/logs/{log}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Organization\"\n//           parent_name_extractor: \"organizations/{organization}\"\n//         }\n//         name_descriptor: {\n//           pattern: \"billingAccounts/{billing_account}/logs/{log}\"\n//           parent_type: \"billing.googleapis.com/BillingAccount\"\n//           parent_name_extractor: \"billingAccounts/{billing_account}\"\n//         }\n//       };\n//     }\n//\n// The ResourceDescriptor Yaml config will look like:\n//\n//     resources:\n//     - type: 'logging.googleapis.com/LogEntry'\n//       name_descriptor:\n//         - pattern: \"projects/{project}/logs/{log}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Project\"\n//           parent_name_extractor: \"projects/{project}\"\n//         - pattern: \"folders/{folder}/logs/{log}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Folder\"\n//           parent_name_extractor: \"folders/{folder}\"\n//         - pattern: \"organizations/{organization}/logs/{log}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Organization\"\n//           parent_name_extractor: \"organizations/{organization}\"\n//         - pattern: \"billingAccounts/{billing_account}/logs/{log}\"\n//           parent_type: \"billing.googleapis.com/BillingAccount\"\n//           parent_name_extractor: \"billingAccounts/{billing_account}\"\n//\n// For flexible resources, the resource name doesn't contain parent names, but\n// the resource itself has parents for policy evaluation.\n//\n// Example:\n//\n//     message Shelf {\n//       option (google.api.resource) = {\n//         type: \"library.googleapis.com/Shelf\"\n//         name_descriptor: {\n//           pattern: \"shelves/{shelf}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Project\"\n//         }\n//         name_descriptor: {\n//           pattern: \"shelves/{shelf}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Folder\"\n//         }\n//       };\n//     }\n//\n// The ResourceDescriptor Yaml config will look like:\n//\n//     resources:\n//     - type: 'library.googleapis.com/Shelf'\n//       name_descriptor:\n//         - pattern: \"shelves/{shelf}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Project\"\n//         - pattern: \"shelves/{shelf}\"\n//           parent_type: \"cloudresourcemanager.googleapis.com/Folder\"\nmessage ResourceDescriptor {\n  // A description of the historical or future-looking state of the\n  // resource pattern.\n  enum History {\n    // The \"unset\" value.\n    HISTORY_UNSPECIFIED = 0;\n\n    // The resource originally had one pattern and launched as such, and\n    // additional patterns were added later.\n    ORIGINALLY_SINGLE_PATTERN = 1;\n\n    // The resource has one pattern, but the API owner expects to add more\n    // later. (This is the inverse of ORIGINALLY_SINGLE_PATTERN, and prevents\n    // that from being necessary once there are multiple patterns.)\n    FUTURE_MULTI_PATTERN = 2;\n  }\n\n  // A flag representing a specific style that a resource claims to conform to.\n  enum Style {\n    // The unspecified value. Do not use.\n    STYLE_UNSPECIFIED = 0;\n\n    // This resource is intended to be \"declarative-friendly\".\n    //\n    // Declarative-friendly resources must be more strictly consistent, and\n    // setting this to true communicates to tools that this resource should\n    // adhere to declarative-friendly expectations.\n    //\n    // Note: This is used by the API linter (linter.aip.dev) to enable\n    // additional checks.\n    DECLARATIVE_FRIENDLY = 1;\n  }\n\n  // The resource type. It must be in the format of\n  // {service_name}/{resource_type_kind}. The `resource_type_kind` must be\n  // singular and must not include version numbers.\n  //\n  // Example: `storage.googleapis.com/Bucket`\n  //\n  // The value of the resource_type_kind must follow the regular expression\n  // /[A-Za-z][a-zA-Z0-9]+/. It should start with an upper case character and\n  // should use PascalCase (UpperCamelCase). The maximum number of\n  // characters allowed for the `resource_type_kind` is 100.\n  string type = 1;\n\n  // Optional. The relative resource name pattern associated with this resource\n  // type. The DNS prefix of the full resource name shouldn't be specified here.\n  //\n  // The path pattern must follow the syntax, which aligns with HTTP binding\n  // syntax:\n  //\n  //     Template = Segment { \"/\" Segment } ;\n  //     Segment = LITERAL | Variable ;\n  //     Variable = \"{\" LITERAL \"}\" ;\n  //\n  // Examples:\n  //\n  //     - \"projects/{project}/topics/{topic}\"\n  //     - \"projects/{project}/knowledgeBases/{knowledge_base}\"\n  //\n  // The components in braces correspond to the IDs for each resource in the\n  // hierarchy. It is expected that, if multiple patterns are provided,\n  // the same component name (e.g. \"project\") refers to IDs of the same\n  // type of resource.\n  repeated string pattern = 2;\n\n  // Optional. The field on the resource that designates the resource name\n  // field. If omitted, this is assumed to be \"name\".\n  string name_field = 3;\n\n  // Optional. The historical or future-looking state of the resource pattern.\n  //\n  // Example:\n  //\n  //     // The InspectTemplate message originally only supported resource\n  //     // names with organization, and project was added later.\n  //     message InspectTemplate {\n  //       option (google.api.resource) = {\n  //         type: \"dlp.googleapis.com/InspectTemplate\"\n  //         pattern:\n  //         \"organizations/{organization}/inspectTemplates/{inspect_template}\"\n  //         pattern: \"projects/{project}/inspectTemplates/{inspect_template}\"\n  //         history: ORIGINALLY_SINGLE_PATTERN\n  //       };\n  //     }\n  History history = 4;\n\n  // The plural name used in the resource name and permission names, such as\n  // 'projects' for the resource name of 'projects/{project}' and the permission\n  // name of 'cloudresourcemanager.googleapis.com/projects.get'. It is the same\n  // concept of the `plural` field in k8s CRD spec\n  // https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/\n  //\n  // Note: The plural form is required even for singleton resources. See\n  // https://aip.dev/156\n  string plural = 5;\n\n  // The same concept of the `singular` field in k8s CRD spec\n  // https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/\n  // Such as \"project\" for the `resourcemanager.googleapis.com/Project` type.\n  string singular = 6;\n\n  // Style flag(s) for this resource.\n  // These indicate that a resource is expected to conform to a given\n  // style. See the specific style flags for additional information.\n  repeated Style style = 10;\n}\n\n// Defines a proto annotation that describes a string field that refers to\n// an API resource.\nmessage ResourceReference {\n  // The resource type that the annotated field references.\n  //\n  // Example:\n  //\n  //     message Subscription {\n  //       string topic = 2 [(google.api.resource_reference) = {\n  //         type: \"pubsub.googleapis.com/Topic\"\n  //       }];\n  //     }\n  //\n  // Occasionally, a field may reference an arbitrary resource. In this case,\n  // APIs use the special value * in their resource reference.\n  //\n  // Example:\n  //\n  //     message GetIamPolicyRequest {\n  //       string resource = 2 [(google.api.resource_reference) = {\n  //         type: \"*\"\n  //       }];\n  //     }\n  string type = 1;\n\n  // The resource type of a child collection that the annotated field\n  // references. This is useful for annotating the `parent` field that\n  // doesn't have a fixed resource type.\n  //\n  // Example:\n  //\n  //     message ListLogEntriesRequest {\n  //       string parent = 1 [(google.api.resource_reference) = {\n  //         child_type: \"logging.googleapis.com/LogEntry\"\n  //       };\n  //     }\n  string child_type = 2;\n}\n"
  },
  {
    "path": "examples/proto/googleapis/google/pubsub/v1/pubsub.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.pubsub.v1;\n\nimport \"google/api/annotations.proto\";\nimport \"google/api/client.proto\";\nimport \"google/api/field_behavior.proto\";\nimport \"google/api/resource.proto\";\nimport \"google/protobuf/duration.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/field_mask.proto\";\nimport \"google/protobuf/timestamp.proto\";\nimport \"google/pubsub/v1/schema.proto\";\n\noption cc_enable_arenas = true;\noption csharp_namespace = \"Google.Cloud.PubSub.V1\";\noption go_package = \"google.golang.org/genproto/googleapis/pubsub/v1;pubsub\";\noption java_multiple_files = true;\noption java_outer_classname = \"PubsubProto\";\noption java_package = \"com.google.pubsub.v1\";\noption php_namespace = \"Google\\\\Cloud\\\\PubSub\\\\V1\";\noption ruby_package = \"Google::Cloud::PubSub::V1\";\n\n// The service that an application uses to manipulate topics, and to send\n// messages to a topic.\nservice Publisher {\n  option (google.api.default_host) = \"pubsub.googleapis.com\";\n  option (google.api.oauth_scopes) =\n      \"https://www.googleapis.com/auth/cloud-platform,\"\n      \"https://www.googleapis.com/auth/pubsub\";\n\n  // Creates the given topic with the given name. See the [resource name rules]\n  // (https://cloud.google.com/pubsub/docs/admin#resource_names).\n  rpc CreateTopic(Topic) returns (Topic) {\n    option (google.api.http) = {\n      put: \"/v1/{name=projects/*/topics/*}\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) = \"name\";\n  }\n\n  // Updates an existing topic. Note that certain properties of a\n  // topic are not modifiable.\n  rpc UpdateTopic(UpdateTopicRequest) returns (Topic) {\n    option (google.api.http) = {\n      patch: \"/v1/{topic.name=projects/*/topics/*}\"\n      body: \"*\"\n    };\n  }\n\n  // Adds one or more messages to the topic. Returns `NOT_FOUND` if the topic\n  // does not exist.\n  rpc Publish(PublishRequest) returns (PublishResponse) {\n    option (google.api.http) = {\n      post: \"/v1/{topic=projects/*/topics/*}:publish\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) = \"topic,messages\";\n  }\n\n  // Gets the configuration of a topic.\n  rpc GetTopic(GetTopicRequest) returns (Topic) {\n    option (google.api.http) = {\n      get: \"/v1/{topic=projects/*/topics/*}\"\n    };\n    option (google.api.method_signature) = \"topic\";\n  }\n\n  // Lists matching topics.\n  rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse) {\n    option (google.api.http) = {\n      get: \"/v1/{project=projects/*}/topics\"\n    };\n    option (google.api.method_signature) = \"project\";\n  }\n\n  // Lists the names of the attached subscriptions on this topic.\n  rpc ListTopicSubscriptions(ListTopicSubscriptionsRequest)\n      returns (ListTopicSubscriptionsResponse) {\n    option (google.api.http) = {\n      get: \"/v1/{topic=projects/*/topics/*}/subscriptions\"\n    };\n    option (google.api.method_signature) = \"topic\";\n  }\n\n  // Lists the names of the snapshots on this topic. Snapshots are used in\n  // [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations,\n  // which allow you to manage message acknowledgments in bulk. That is, you can\n  // set the acknowledgment state of messages in an existing subscription to the\n  // state captured by a snapshot.\n  rpc ListTopicSnapshots(ListTopicSnapshotsRequest)\n      returns (ListTopicSnapshotsResponse) {\n    option (google.api.http) = {\n      get: \"/v1/{topic=projects/*/topics/*}/snapshots\"\n    };\n    option (google.api.method_signature) = \"topic\";\n  }\n\n  // Deletes the topic with the given name. Returns `NOT_FOUND` if the topic\n  // does not exist. After a topic is deleted, a new topic may be created with\n  // the same name; this is an entirely new topic with none of the old\n  // configuration or subscriptions. Existing subscriptions to this topic are\n  // not deleted, but their `topic` field is set to `_deleted-topic_`.\n  rpc DeleteTopic(DeleteTopicRequest) returns (google.protobuf.Empty) {\n    option (google.api.http) = {\n      delete: \"/v1/{topic=projects/*/topics/*}\"\n    };\n    option (google.api.method_signature) = \"topic\";\n  }\n\n  // Detaches a subscription from this topic. All messages retained in the\n  // subscription are dropped. Subsequent `Pull` and `StreamingPull` requests\n  // will return FAILED_PRECONDITION. If the subscription is a push\n  // subscription, pushes to the endpoint will stop.\n  rpc DetachSubscription(DetachSubscriptionRequest)\n      returns (DetachSubscriptionResponse) {\n    option (google.api.http) = {\n      post: \"/v1/{subscription=projects/*/subscriptions/*}:detach\"\n    };\n  }\n}\n\n// A policy constraining the storage of messages published to the topic.\nmessage MessageStoragePolicy {\n  // A list of IDs of GCP regions where messages that are published to the topic\n  // may be persisted in storage. Messages published by publishers running in\n  // non-allowed GCP regions (or running outside of GCP altogether) will be\n  // routed for storage in one of the allowed regions. An empty list means that\n  // no regions are allowed, and is not a valid configuration.\n  repeated string allowed_persistence_regions = 1;\n}\n\n// Settings for validating messages published against a schema.\nmessage SchemaSettings {\n  // Required. The name of the schema that messages published should be\n  // validated against. Format is `projects/{project}/schemas/{schema}`. The\n  // value of this field will be `_deleted-schema_` if the schema has been\n  // deleted.\n  string schema = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Schema\" }\n  ];\n\n  // The encoding of messages validated against `schema`.\n  Encoding encoding = 2;\n}\n\n// A topic resource.\nmessage Topic {\n  option (google.api.resource) = {\n    type: \"pubsub.googleapis.com/Topic\"\n    pattern: \"projects/{project}/topics/{topic}\"\n    pattern: \"_deleted-topic_\"\n  };\n\n  // Required. The name of the topic. It must have the format\n  // `\"projects/{project}/topics/{topic}\"`. `{topic}` must start with a letter,\n  // and contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`),\n  // underscores (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent\n  // signs (`%`). It must be between 3 and 255 characters in length, and it\n  // must not start with `\"goog\"`.\n  string name = 1 [(google.api.field_behavior) = REQUIRED];\n\n  // See [Creating and managing labels]\n  // (https://cloud.google.com/pubsub/docs/labels).\n  map<string, string> labels = 2;\n\n  // Policy constraining the set of Google Cloud Platform regions where messages\n  // published to the topic may be stored. If not present, then no constraints\n  // are in effect.\n  MessageStoragePolicy message_storage_policy = 3;\n\n  // The resource name of the Cloud KMS CryptoKey to be used to protect access\n  // to messages published on this topic.\n  //\n  // The expected format is `projects/*/locations/*/keyRings/*/cryptoKeys/*`.\n  string kms_key_name = 5;\n\n  // Settings for validating messages published against a schema.\n  //\n  // EXPERIMENTAL: Schema support is in development and may not work yet.\n  SchemaSettings schema_settings = 6;\n\n  // Reserved for future use. This field is set only in responses from the\n  // server; it is ignored if it is set in any requests.\n  bool satisfies_pzs = 7;\n}\n\n// A message that is published by publishers and consumed by subscribers. The\n// message must contain either a non-empty data field or at least one attribute.\n// Note that client libraries represent this object differently\n// depending on the language. See the corresponding [client library\n// documentation](https://cloud.google.com/pubsub/docs/reference/libraries) for\n// more information. See [quotas and limits]\n// (https://cloud.google.com/pubsub/quotas) for more information about message\n// limits.\nmessage PubsubMessage {\n  // The message data field. If this field is empty, the message must contain\n  // at least one attribute.\n  bytes data = 1;\n\n  // Attributes for this message. If this field is empty, the message must\n  // contain non-empty data. This can be used to filter messages on the\n  // subscription.\n  map<string, string> attributes = 2;\n\n  // ID of this message, assigned by the server when the message is published.\n  // Guaranteed to be unique within the topic. This value may be read by a\n  // subscriber that receives a `PubsubMessage` via a `Pull` call or a push\n  // delivery. It must not be populated by the publisher in a `Publish` call.\n  string message_id = 3;\n\n  // The time at which the message was published, populated by the server when\n  // it receives the `Publish` call. It must not be populated by the\n  // publisher in a `Publish` call.\n  google.protobuf.Timestamp publish_time = 4;\n\n  // If non-empty, identifies related messages for which publish order should be\n  // respected. If a `Subscription` has `enable_message_ordering` set to `true`,\n  // messages published with the same non-empty `ordering_key` value will be\n  // delivered to subscribers in the order in which they are received by the\n  // Pub/Sub system. All `PubsubMessage`s published in a given `PublishRequest`\n  // must specify the same `ordering_key` value.\n  string ordering_key = 5;\n}\n\n// Request for the GetTopic method.\nmessage GetTopicRequest {\n  // Required. The name of the topic to get.\n  // Format is `projects/{project}/topics/{topic}`.\n  string topic = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Topic\" }\n  ];\n}\n\n// Request for the UpdateTopic method.\nmessage UpdateTopicRequest {\n  // Required. The updated topic object.\n  Topic topic = 1 [(google.api.field_behavior) = REQUIRED];\n\n  // Required. Indicates which fields in the provided topic to update. Must be\n  // specified and non-empty. Note that if `update_mask` contains\n  // \"message_storage_policy\" but the `message_storage_policy` is not set in\n  // the `topic` provided above, then the updated value is determined by the\n  // policy configured at the project or organization level.\n  google.protobuf.FieldMask update_mask = 2\n      [(google.api.field_behavior) = REQUIRED];\n}\n\n// Request for the Publish method.\nmessage PublishRequest {\n  // Required. The messages in the request will be published on this topic.\n  // Format is `projects/{project}/topics/{topic}`.\n  string topic = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Topic\" }\n  ];\n\n  // Required. The messages to publish.\n  repeated PubsubMessage messages = 2 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Response for the `Publish` method.\nmessage PublishResponse {\n  // The server-assigned ID of each published message, in the same order as\n  // the messages in the request. IDs are guaranteed to be unique within\n  // the topic.\n  repeated string message_ids = 1;\n}\n\n// Request for the `ListTopics` method.\nmessage ListTopicsRequest {\n  // Required. The name of the project in which to list topics.\n  // Format is `projects/{project-id}`.\n  string project = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"cloudresourcemanager.googleapis.com/Project\"\n    }\n  ];\n\n  // Maximum number of topics to return.\n  int32 page_size = 2;\n\n  // The value returned by the last `ListTopicsResponse`; indicates that this is\n  // a continuation of a prior `ListTopics` call, and that the system should\n  // return the next page of data.\n  string page_token = 3;\n}\n\n// Response for the `ListTopics` method.\nmessage ListTopicsResponse {\n  // The resulting topics.\n  repeated Topic topics = 1;\n\n  // If not empty, indicates that there may be more topics that match the\n  // request; this value should be passed in a new `ListTopicsRequest`.\n  string next_page_token = 2;\n}\n\n// Request for the `ListTopicSubscriptions` method.\nmessage ListTopicSubscriptionsRequest {\n  // Required. The name of the topic that subscriptions are attached to.\n  // Format is `projects/{project}/topics/{topic}`.\n  string topic = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Topic\" }\n  ];\n\n  // Maximum number of subscription names to return.\n  int32 page_size = 2;\n\n  // The value returned by the last `ListTopicSubscriptionsResponse`; indicates\n  // that this is a continuation of a prior `ListTopicSubscriptions` call, and\n  // that the system should return the next page of data.\n  string page_token = 3;\n}\n\n// Response for the `ListTopicSubscriptions` method.\nmessage ListTopicSubscriptionsResponse {\n  // The names of subscriptions attached to the topic specified in the request.\n  repeated string subscriptions = 1 [(google.api.resource_reference) = {\n    type: \"pubsub.googleapis.com/Subscription\"\n  }];\n\n  // If not empty, indicates that there may be more subscriptions that match\n  // the request; this value should be passed in a new\n  // `ListTopicSubscriptionsRequest` to get more subscriptions.\n  string next_page_token = 2;\n}\n\n// Request for the `ListTopicSnapshots` method.\nmessage ListTopicSnapshotsRequest {\n  // Required. The name of the topic that snapshots are attached to.\n  // Format is `projects/{project}/topics/{topic}`.\n  string topic = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Topic\" }\n  ];\n\n  // Maximum number of snapshot names to return.\n  int32 page_size = 2;\n\n  // The value returned by the last `ListTopicSnapshotsResponse`; indicates\n  // that this is a continuation of a prior `ListTopicSnapshots` call, and\n  // that the system should return the next page of data.\n  string page_token = 3;\n}\n\n// Response for the `ListTopicSnapshots` method.\nmessage ListTopicSnapshotsResponse {\n  // The names of the snapshots that match the request.\n  repeated string snapshots = 1;\n\n  // If not empty, indicates that there may be more snapshots that match\n  // the request; this value should be passed in a new\n  // `ListTopicSnapshotsRequest` to get more snapshots.\n  string next_page_token = 2;\n}\n\n// Request for the `DeleteTopic` method.\nmessage DeleteTopicRequest {\n  // Required. Name of the topic to delete.\n  // Format is `projects/{project}/topics/{topic}`.\n  string topic = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Topic\" }\n  ];\n}\n\n// Request for the DetachSubscription method.\nmessage DetachSubscriptionRequest {\n  // Required. The subscription to detach.\n  // Format is `projects/{project}/subscriptions/{subscription}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n}\n\n// Response for the DetachSubscription method.\n// Reserved for future use.\nmessage DetachSubscriptionResponse {}\n\n// The service that an application uses to manipulate subscriptions and to\n// consume messages from a subscription via the `Pull` method or by\n// establishing a bi-directional stream using the `StreamingPull` method.\nservice Subscriber {\n  option (google.api.default_host) = \"pubsub.googleapis.com\";\n  option (google.api.oauth_scopes) =\n      \"https://www.googleapis.com/auth/cloud-platform,\"\n      \"https://www.googleapis.com/auth/pubsub\";\n\n  // Creates a subscription to a given topic. See the [resource name rules]\n  // (https://cloud.google.com/pubsub/docs/admin#resource_names).\n  // If the subscription already exists, returns `ALREADY_EXISTS`.\n  // If the corresponding topic doesn't exist, returns `NOT_FOUND`.\n  //\n  // If the name is not provided in the request, the server will assign a random\n  // name for this subscription on the same project as the topic, conforming\n  // to the [resource name format]\n  // (https://cloud.google.com/pubsub/docs/admin#resource_names). The generated\n  // name is populated in the returned Subscription object. Note that for REST\n  // API requests, you must specify a name in the request.\n  rpc CreateSubscription(Subscription) returns (Subscription) {\n    option (google.api.http) = {\n      put: \"/v1/{name=projects/*/subscriptions/*}\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) =\n        \"name,topic,push_config,ack_deadline_seconds\";\n  }\n\n  // Gets the configuration details of a subscription.\n  rpc GetSubscription(GetSubscriptionRequest) returns (Subscription) {\n    option (google.api.http) = {\n      get: \"/v1/{subscription=projects/*/subscriptions/*}\"\n    };\n    option (google.api.method_signature) = \"subscription\";\n  }\n\n  // Updates an existing subscription. Note that certain properties of a\n  // subscription, such as its topic, are not modifiable.\n  rpc UpdateSubscription(UpdateSubscriptionRequest) returns (Subscription) {\n    option (google.api.http) = {\n      patch: \"/v1/{subscription.name=projects/*/subscriptions/*}\"\n      body: \"*\"\n    };\n  }\n\n  // Lists matching subscriptions.\n  rpc ListSubscriptions(ListSubscriptionsRequest)\n      returns (ListSubscriptionsResponse) {\n    option (google.api.http) = {\n      get: \"/v1/{project=projects/*}/subscriptions\"\n    };\n    option (google.api.method_signature) = \"project\";\n  }\n\n  // Deletes an existing subscription. All messages retained in the subscription\n  // are immediately dropped. Calls to `Pull` after deletion will return\n  // `NOT_FOUND`. After a subscription is deleted, a new one may be created with\n  // the same name, but the new one has no association with the old\n  // subscription or its topic unless the same topic is specified.\n  rpc DeleteSubscription(DeleteSubscriptionRequest)\n      returns (google.protobuf.Empty) {\n    option (google.api.http) = {\n      delete: \"/v1/{subscription=projects/*/subscriptions/*}\"\n    };\n    option (google.api.method_signature) = \"subscription\";\n  }\n\n  // Modifies the ack deadline for a specific message. This method is useful\n  // to indicate that more time is needed to process a message by the\n  // subscriber, or to make the message available for redelivery if the\n  // processing was interrupted. Note that this does not modify the\n  // subscription-level `ackDeadlineSeconds` used for subsequent messages.\n  rpc ModifyAckDeadline(ModifyAckDeadlineRequest)\n      returns (google.protobuf.Empty) {\n    option (google.api.http) = {\n      post: \"/v1/{subscription=projects/*/subscriptions/*}:modifyAckDeadline\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) =\n        \"subscription,ack_ids,ack_deadline_seconds\";\n  }\n\n  // Acknowledges the messages associated with the `ack_ids` in the\n  // `AcknowledgeRequest`. The Pub/Sub system can remove the relevant messages\n  // from the subscription.\n  //\n  // Acknowledging a message whose ack deadline has expired may succeed,\n  // but such a message may be redelivered later. Acknowledging a message more\n  // than once will not result in an error.\n  rpc Acknowledge(AcknowledgeRequest) returns (google.protobuf.Empty) {\n    option (google.api.http) = {\n      post: \"/v1/{subscription=projects/*/subscriptions/*}:acknowledge\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) = \"subscription,ack_ids\";\n  }\n\n  // Pulls messages from the server. The server may return `UNAVAILABLE` if\n  // there are too many concurrent pull requests pending for the given\n  // subscription.\n  rpc Pull(PullRequest) returns (PullResponse) {\n    option (google.api.http) = {\n      post: \"/v1/{subscription=projects/*/subscriptions/*}:pull\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) =\n        \"subscription,return_immediately,max_messages\";\n  }\n\n  // Establishes a stream with the server, which sends messages down to the\n  // client. The client streams acknowledgements and ack deadline modifications\n  // back to the server. The server will close the stream and return the status\n  // on any error. The server may close the stream with status `UNAVAILABLE` to\n  // reassign server-side resources, in which case, the client should\n  // re-establish the stream. Flow control can be achieved by configuring the\n  // underlying RPC channel.\n  rpc StreamingPull(stream StreamingPullRequest)\n      returns (stream StreamingPullResponse) {}\n\n  // Modifies the `PushConfig` for a specified subscription.\n  //\n  // This may be used to change a push subscription to a pull one (signified by\n  // an empty `PushConfig`) or vice versa, or change the endpoint URL and other\n  // attributes of a push subscription. Messages will accumulate for delivery\n  // continuously through the call regardless of changes to the `PushConfig`.\n  rpc ModifyPushConfig(ModifyPushConfigRequest)\n      returns (google.protobuf.Empty) {\n    option (google.api.http) = {\n      post: \"/v1/{subscription=projects/*/subscriptions/*}:modifyPushConfig\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) = \"subscription,push_config\";\n  }\n\n  // Gets the configuration details of a snapshot. Snapshots are used in\n  // <a href=\"https://cloud.google.com/pubsub/docs/replay-overview\">Seek</a>\n  // operations, which allow you to manage message acknowledgments in bulk. That\n  // is, you can set the acknowledgment state of messages in an existing\n  // subscription to the state captured by a snapshot.\n  rpc GetSnapshot(GetSnapshotRequest) returns (Snapshot) {\n    option (google.api.http) = {\n      get: \"/v1/{snapshot=projects/*/snapshots/*}\"\n    };\n    option (google.api.method_signature) = \"snapshot\";\n  }\n\n  // Lists the existing snapshots. Snapshots are used in [Seek](\n  // https://cloud.google.com/pubsub/docs/replay-overview) operations, which\n  // allow you to manage message acknowledgments in bulk. That is, you can set\n  // the acknowledgment state of messages in an existing subscription to the\n  // state captured by a snapshot.\n  rpc ListSnapshots(ListSnapshotsRequest) returns (ListSnapshotsResponse) {\n    option (google.api.http) = {\n      get: \"/v1/{project=projects/*}/snapshots\"\n    };\n    option (google.api.method_signature) = \"project\";\n  }\n\n  // Creates a snapshot from the requested subscription. Snapshots are used in\n  // [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations,\n  // which allow you to manage message acknowledgments in bulk. That is, you can\n  // set the acknowledgment state of messages in an existing subscription to the\n  // state captured by a snapshot.\n  // If the snapshot already exists, returns `ALREADY_EXISTS`.\n  // If the requested subscription doesn't exist, returns `NOT_FOUND`.\n  // If the backlog in the subscription is too old -- and the resulting snapshot\n  // would expire in less than 1 hour -- then `FAILED_PRECONDITION` is returned.\n  // See also the `Snapshot.expire_time` field. If the name is not provided in\n  // the request, the server will assign a random\n  // name for this snapshot on the same project as the subscription, conforming\n  // to the [resource name format]\n  // (https://cloud.google.com/pubsub/docs/admin#resource_names). The\n  // generated name is populated in the returned Snapshot object. Note that for\n  // REST API requests, you must specify a name in the request.\n  rpc CreateSnapshot(CreateSnapshotRequest) returns (Snapshot) {\n    option (google.api.http) = {\n      put: \"/v1/{name=projects/*/snapshots/*}\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) = \"name,subscription\";\n  }\n\n  // Updates an existing snapshot. Snapshots are used in\n  // <a href=\"https://cloud.google.com/pubsub/docs/replay-overview\">Seek</a>\n  // operations, which allow\n  // you to manage message acknowledgments in bulk. That is, you can set the\n  // acknowledgment state of messages in an existing subscription to the state\n  // captured by a snapshot.\n  rpc UpdateSnapshot(UpdateSnapshotRequest) returns (Snapshot) {\n    option (google.api.http) = {\n      patch: \"/v1/{snapshot.name=projects/*/snapshots/*}\"\n      body: \"*\"\n    };\n  }\n\n  // Removes an existing snapshot. Snapshots are used in [Seek]\n  // (https://cloud.google.com/pubsub/docs/replay-overview) operations, which\n  // allow you to manage message acknowledgments in bulk. That is, you can set\n  // the acknowledgment state of messages in an existing subscription to the\n  // state captured by a snapshot.\n  // When the snapshot is deleted, all messages retained in the snapshot\n  // are immediately dropped. After a snapshot is deleted, a new one may be\n  // created with the same name, but the new one has no association with the old\n  // snapshot or its subscription, unless the same subscription is specified.\n  rpc DeleteSnapshot(DeleteSnapshotRequest) returns (google.protobuf.Empty) {\n    option (google.api.http) = {\n      delete: \"/v1/{snapshot=projects/*/snapshots/*}\"\n    };\n    option (google.api.method_signature) = \"snapshot\";\n  }\n\n  // Seeks an existing subscription to a point in time or to a given snapshot,\n  // whichever is provided in the request. Snapshots are used in [Seek]\n  // (https://cloud.google.com/pubsub/docs/replay-overview) operations, which\n  // allow you to manage message acknowledgments in bulk. That is, you can set\n  // the acknowledgment state of messages in an existing subscription to the\n  // state captured by a snapshot. Note that both the subscription and the\n  // snapshot must be on the same topic.\n  rpc Seek(SeekRequest) returns (SeekResponse) {\n    option (google.api.http) = {\n      post: \"/v1/{subscription=projects/*/subscriptions/*}:seek\"\n      body: \"*\"\n    };\n  }\n}\n\n// A subscription resource.\nmessage Subscription {\n  option (google.api.resource) = {\n    type: \"pubsub.googleapis.com/Subscription\"\n    pattern: \"projects/{project}/subscriptions/{subscription}\"\n  };\n\n  // Required. The name of the subscription. It must have the format\n  // `\"projects/{project}/subscriptions/{subscription}\"`. `{subscription}` must\n  // start with a letter, and contain only letters (`[A-Za-z]`), numbers\n  // (`[0-9]`), dashes (`-`), underscores (`_`), periods (`.`), tildes (`~`),\n  // plus (`+`) or percent signs (`%`). It must be between 3 and 255 characters\n  // in length, and it must not start with `\"goog\"`.\n  string name = 1 [(google.api.field_behavior) = REQUIRED];\n\n  // Required. The name of the topic from which this subscription is receiving\n  // messages. Format is `projects/{project}/topics/{topic}`. The value of this\n  // field will be `_deleted-topic_` if the topic has been deleted.\n  string topic = 2 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Topic\" }\n  ];\n\n  // If push delivery is used with this subscription, this field is\n  // used to configure it. An empty `pushConfig` signifies that the subscriber\n  // will pull and ack messages using API methods.\n  PushConfig push_config = 4;\n\n  // The approximate amount of time (on a best-effort basis) Pub/Sub waits for\n  // the subscriber to acknowledge receipt before resending the message. In the\n  // interval after the message is delivered and before it is acknowledged, it\n  // is considered to be <i>outstanding</i>. During that time period, the\n  // message will not be redelivered (on a best-effort basis).\n  //\n  // For pull subscriptions, this value is used as the initial value for the ack\n  // deadline. To override this value for a given message, call\n  // `ModifyAckDeadline` with the corresponding `ack_id` if using\n  // non-streaming pull or send the `ack_id` in a\n  // `StreamingModifyAckDeadlineRequest` if using streaming pull.\n  // The minimum custom deadline you can specify is 10 seconds.\n  // The maximum custom deadline you can specify is 600 seconds (10 minutes).\n  // If this parameter is 0, a default value of 10 seconds is used.\n  //\n  // For push delivery, this value is also used to set the request timeout for\n  // the call to the push endpoint.\n  //\n  // If the subscriber never acknowledges the message, the Pub/Sub\n  // system will eventually redeliver the message.\n  int32 ack_deadline_seconds = 5;\n\n  // Indicates whether to retain acknowledged messages. If true, then\n  // messages are not expunged from the subscription's backlog, even if they are\n  // acknowledged, until they fall out of the `message_retention_duration`\n  // window. This must be true if you would like to [Seek to a timestamp]\n  // (https://cloud.google.com/pubsub/docs/replay-overview#seek_to_a_time).\n  bool retain_acked_messages = 7;\n\n  // How long to retain unacknowledged messages in the subscription's backlog,\n  // from the moment a message is published.\n  // If `retain_acked_messages` is true, then this also configures the retention\n  // of acknowledged messages, and thus configures how far back in time a `Seek`\n  // can be done. Defaults to 7 days. Cannot be more than 7 days or less than 10\n  // minutes.\n  google.protobuf.Duration message_retention_duration = 8;\n\n  // See <a href=\"https://cloud.google.com/pubsub/docs/labels\"> Creating and\n  // managing labels</a>.\n  map<string, string> labels = 9;\n\n  // If true, messages published with the same `ordering_key` in `PubsubMessage`\n  // will be delivered to the subscribers in the order in which they\n  // are received by the Pub/Sub system. Otherwise, they may be delivered in\n  // any order.\n  bool enable_message_ordering = 10;\n\n  // A policy that specifies the conditions for this subscription's expiration.\n  // A subscription is considered active as long as any connected subscriber is\n  // successfully consuming messages from the subscription or is issuing\n  // operations on the subscription. If `expiration_policy` is not set, a\n  // *default policy* with `ttl` of 31 days will be used. The minimum allowed\n  // value for `expiration_policy.ttl` is 1 day.\n  ExpirationPolicy expiration_policy = 11;\n\n  // An expression written in the Pub/Sub [filter\n  // language](https://cloud.google.com/pubsub/docs/filtering). If non-empty,\n  // then only `PubsubMessage`s whose `attributes` field matches the filter are\n  // delivered on this subscription. If empty, then no messages are filtered\n  // out.\n  string filter = 12;\n\n  // A policy that specifies the conditions for dead lettering messages in\n  // this subscription. If dead_letter_policy is not set, dead lettering\n  // is disabled.\n  //\n  // The Cloud Pub/Sub service account associated with this subscriptions's\n  // parent project (i.e.,\n  // service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) must have\n  // permission to Acknowledge() messages on this subscription.\n  DeadLetterPolicy dead_letter_policy = 13;\n\n  // A policy that specifies how Pub/Sub retries message delivery for this\n  // subscription.\n  //\n  // If not set, the default retry policy is applied. This generally implies\n  // that messages will be retried as soon as possible for healthy subscribers.\n  // RetryPolicy will be triggered on NACKs or acknowledgement deadline\n  // exceeded events for a given message.\n  RetryPolicy retry_policy = 14;\n\n  // Indicates whether the subscription is detached from its topic. Detached\n  // subscriptions don't receive messages from their topic and don't retain any\n  // backlog. `Pull` and `StreamingPull` requests will return\n  // FAILED_PRECONDITION. If the subscription is a push subscription, pushes to\n  // the endpoint will not be made.\n  bool detached = 15;\n}\n\n// A policy that specifies how Cloud Pub/Sub retries message delivery.\n//\n// Retry delay will be exponential based on provided minimum and maximum\n// backoffs. https://en.wikipedia.org/wiki/Exponential_backoff.\n//\n// RetryPolicy will be triggered on NACKs or acknowledgement deadline exceeded\n// events for a given message.\n//\n// Retry Policy is implemented on a best effort basis. At times, the delay\n// between consecutive deliveries may not match the configuration. That is,\n// delay can be more or less than configured backoff.\nmessage RetryPolicy {\n  // The minimum delay between consecutive deliveries of a given message.\n  // Value should be between 0 and 600 seconds. Defaults to 10 seconds.\n  google.protobuf.Duration minimum_backoff = 1;\n\n  // The maximum delay between consecutive deliveries of a given message.\n  // Value should be between 0 and 600 seconds. Defaults to 600 seconds.\n  google.protobuf.Duration maximum_backoff = 2;\n}\n\n// Dead lettering is done on a best effort basis. The same message might be\n// dead lettered multiple times.\n//\n// If validation on any of the fields fails at subscription creation/updation,\n// the create/update subscription request will fail.\nmessage DeadLetterPolicy {\n  // The name of the topic to which dead letter messages should be published.\n  // Format is `projects/{project}/topics/{topic}`.The Cloud Pub/Sub service\n  // account associated with the enclosing subscription's parent project (i.e.,\n  // service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) must have\n  // permission to Publish() to this topic.\n  //\n  // The operation will fail if the topic does not exist.\n  // Users should ensure that there is a subscription attached to this topic\n  // since messages published to a topic with no subscriptions are lost.\n  string dead_letter_topic = 1;\n\n  // The maximum number of delivery attempts for any message. The value must be\n  // between 5 and 100.\n  //\n  // The number of delivery attempts is defined as 1 + (the sum of number of\n  // NACKs and number of times the acknowledgement deadline has been exceeded\n  // for the message).\n  //\n  // A NACK is any call to ModifyAckDeadline with a 0 deadline. Note that\n  // client libraries may automatically extend ack_deadlines.\n  //\n  // This field will be honored on a best effort basis.\n  //\n  // If this parameter is 0, a default value of 5 is used.\n  int32 max_delivery_attempts = 2;\n}\n\n// A policy that specifies the conditions for resource expiration (i.e.,\n// automatic resource deletion).\nmessage ExpirationPolicy {\n  // Specifies the \"time-to-live\" duration for an associated resource. The\n  // resource expires if it is not active for a period of `ttl`. The definition\n  // of \"activity\" depends on the type of the associated resource. The minimum\n  // and maximum allowed values for `ttl` depend on the type of the associated\n  // resource, as well. If `ttl` is not set, the associated resource never\n  // expires.\n  google.protobuf.Duration ttl = 1;\n}\n\n// Configuration for a push delivery endpoint.\nmessage PushConfig {\n  // Contains information needed for generating an\n  // [OpenID Connect\n  // token](https://developers.google.com/identity/protocols/OpenIDConnect).\n  message OidcToken {\n    // [Service account\n    // email](https://cloud.google.com/iam/docs/service-accounts)\n    // to be used for generating the OIDC token. The caller (for\n    // CreateSubscription, UpdateSubscription, and ModifyPushConfig RPCs) must\n    // have the iam.serviceAccounts.actAs permission for the service account.\n    string service_account_email = 1;\n\n    // Audience to be used when generating OIDC token. The audience claim\n    // identifies the recipients that the JWT is intended for. The audience\n    // value is a single case-sensitive string. Having multiple values (array)\n    // for the audience field is not supported. More info about the OIDC JWT\n    // token audience here: https://tools.ietf.org/html/rfc7519#section-4.1.3\n    // Note: if not specified, the Push endpoint URL will be used.\n    string audience = 2;\n  }\n\n  // A URL locating the endpoint to which messages should be pushed.\n  // For example, a Webhook endpoint might use `https://example.com/push`.\n  string push_endpoint = 1;\n\n  // Endpoint configuration attributes that can be used to control different\n  // aspects of the message delivery.\n  //\n  // The only currently supported attribute is `x-goog-version`, which you can\n  // use to change the format of the pushed message. This attribute\n  // indicates the version of the data expected by the endpoint. This\n  // controls the shape of the pushed message (i.e., its fields and metadata).\n  //\n  // If not present during the `CreateSubscription` call, it will default to\n  // the version of the Pub/Sub API used to make such call. If not present in a\n  // `ModifyPushConfig` call, its value will not be changed. `GetSubscription`\n  // calls will always return a valid version, even if the subscription was\n  // created without this attribute.\n  //\n  // The only supported values for the `x-goog-version` attribute are:\n  //\n  // * `v1beta1`: uses the push format defined in the v1beta1 Pub/Sub API.\n  // * `v1` or `v1beta2`: uses the push format defined in the v1 Pub/Sub API.\n  //\n  // For example:\n  // <pre><code>attributes { \"x-goog-version\": \"v1\" } </code></pre>\n  map<string, string> attributes = 2;\n\n  // An authentication method used by push endpoints to verify the source of\n  // push requests. This can be used with push endpoints that are private by\n  // default to allow requests only from the Cloud Pub/Sub system, for example.\n  // This field is optional and should be set only by users interested in\n  // authenticated push.\n  oneof authentication_method {\n    // If specified, Pub/Sub will generate and attach an OIDC JWT token as an\n    // `Authorization` header in the HTTP request for every pushed message.\n    OidcToken oidc_token = 3;\n  }\n}\n\n// A message and its corresponding acknowledgment ID.\nmessage ReceivedMessage {\n  // This ID can be used to acknowledge the received message.\n  string ack_id = 1;\n\n  // The message.\n  PubsubMessage message = 2;\n\n  // The approximate number of times that Cloud Pub/Sub has attempted to deliver\n  // the associated message to a subscriber.\n  //\n  // More precisely, this is 1 + (number of NACKs) +\n  // (number of ack_deadline exceeds) for this message.\n  //\n  // A NACK is any call to ModifyAckDeadline with a 0 deadline. An ack_deadline\n  // exceeds event is whenever a message is not acknowledged within\n  // ack_deadline. Note that ack_deadline is initially\n  // Subscription.ackDeadlineSeconds, but may get extended automatically by\n  // the client library.\n  //\n  // Upon the first delivery of a given message, `delivery_attempt` will have a\n  // value of 1. The value is calculated at best effort and is approximate.\n  //\n  // If a DeadLetterPolicy is not set on the subscription, this will be 0.\n  int32 delivery_attempt = 3;\n}\n\n// Request for the GetSubscription method.\nmessage GetSubscriptionRequest {\n  // Required. The name of the subscription to get.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n}\n\n// Request for the UpdateSubscription method.\nmessage UpdateSubscriptionRequest {\n  // Required. The updated subscription object.\n  Subscription subscription = 1 [(google.api.field_behavior) = REQUIRED];\n\n  // Required. Indicates which fields in the provided subscription to update.\n  // Must be specified and non-empty.\n  google.protobuf.FieldMask update_mask = 2\n      [(google.api.field_behavior) = REQUIRED];\n}\n\n// Request for the `ListSubscriptions` method.\nmessage ListSubscriptionsRequest {\n  // Required. The name of the project in which to list subscriptions.\n  // Format is `projects/{project-id}`.\n  string project = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"cloudresourcemanager.googleapis.com/Project\"\n    }\n  ];\n\n  // Maximum number of subscriptions to return.\n  int32 page_size = 2;\n\n  // The value returned by the last `ListSubscriptionsResponse`; indicates that\n  // this is a continuation of a prior `ListSubscriptions` call, and that the\n  // system should return the next page of data.\n  string page_token = 3;\n}\n\n// Response for the `ListSubscriptions` method.\nmessage ListSubscriptionsResponse {\n  // The subscriptions that match the request.\n  repeated Subscription subscriptions = 1;\n\n  // If not empty, indicates that there may be more subscriptions that match\n  // the request; this value should be passed in a new\n  // `ListSubscriptionsRequest` to get more subscriptions.\n  string next_page_token = 2;\n}\n\n// Request for the DeleteSubscription method.\nmessage DeleteSubscriptionRequest {\n  // Required. The subscription to delete.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n}\n\n// Request for the ModifyPushConfig method.\nmessage ModifyPushConfigRequest {\n  // Required. The name of the subscription.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n\n  // Required. The push configuration for future deliveries.\n  //\n  // An empty `pushConfig` indicates that the Pub/Sub system should\n  // stop pushing messages from the given subscription and allow\n  // messages to be pulled and acknowledged - effectively pausing\n  // the subscription if `Pull` or `StreamingPull` is not called.\n  PushConfig push_config = 2 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Request for the `Pull` method.\nmessage PullRequest {\n  // Required. The subscription from which messages should be pulled.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n\n  // Optional. If this field set to true, the system will respond immediately\n  // even if it there are no messages available to return in the `Pull`\n  // response. Otherwise, the system may wait (for a bounded amount of time)\n  // until at least one message is available, rather than returning no messages.\n  // Warning: setting this field to `true` is discouraged because it adversely\n  // impacts the performance of `Pull` operations. We recommend that users do\n  // not set this field.\n  bool return_immediately = 2\n      [deprecated = true, (google.api.field_behavior) = OPTIONAL];\n\n  // Required. The maximum number of messages to return for this request. Must\n  // be a positive integer. The Pub/Sub system may return fewer than the number\n  // specified.\n  int32 max_messages = 3 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Response for the `Pull` method.\nmessage PullResponse {\n  // Received Pub/Sub messages. The list will be empty if there are no more\n  // messages available in the backlog. For JSON, the response can be entirely\n  // empty. The Pub/Sub system may return fewer than the `maxMessages` requested\n  // even if there are more messages available in the backlog.\n  repeated ReceivedMessage received_messages = 1;\n}\n\n// Request for the ModifyAckDeadline method.\nmessage ModifyAckDeadlineRequest {\n  // Required. The name of the subscription.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n\n  // Required. List of acknowledgment IDs.\n  repeated string ack_ids = 4 [(google.api.field_behavior) = REQUIRED];\n\n  // Required. The new ack deadline with respect to the time this request was\n  // sent to the Pub/Sub system. For example, if the value is 10, the new ack\n  // deadline will expire 10 seconds after the `ModifyAckDeadline` call was\n  // made. Specifying zero might immediately make the message available for\n  // delivery to another subscriber client. This typically results in an\n  // increase in the rate of message redeliveries (that is, duplicates).\n  // The minimum deadline you can specify is 0 seconds.\n  // The maximum deadline you can specify is 600 seconds (10 minutes).\n  int32 ack_deadline_seconds = 3 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Request for the Acknowledge method.\nmessage AcknowledgeRequest {\n  // Required. The subscription whose message is being acknowledged.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n\n  // Required. The acknowledgment ID for the messages being acknowledged that\n  // was returned by the Pub/Sub system in the `Pull` response. Must not be\n  // empty.\n  repeated string ack_ids = 2 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Request for the `StreamingPull` streaming RPC method. This request is used to\n// establish the initial stream as well as to stream acknowledgements and ack\n// deadline modifications from the client to the server.\nmessage StreamingPullRequest {\n  // Required. The subscription for which to initialize the new stream. This\n  // must be provided in the first request on the stream, and must not be set in\n  // subsequent requests from client to server.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n\n  // List of acknowledgement IDs for acknowledging previously received messages\n  // (received on this stream or a different stream). If an ack ID has expired,\n  // the corresponding message may be redelivered later. Acknowledging a message\n  // more than once will not result in an error. If the acknowledgement ID is\n  // malformed, the stream will be aborted with status `INVALID_ARGUMENT`.\n  repeated string ack_ids = 2;\n\n  // The list of new ack deadlines for the IDs listed in\n  // `modify_deadline_ack_ids`. The size of this list must be the same as the\n  // size of `modify_deadline_ack_ids`. If it differs the stream will be aborted\n  // with `INVALID_ARGUMENT`. Each element in this list is applied to the\n  // element in the same position in `modify_deadline_ack_ids`. The new ack\n  // deadline is with respect to the time this request was sent to the Pub/Sub\n  // system. Must be >= 0. For example, if the value is 10, the new ack deadline\n  // will expire 10 seconds after this request is received. If the value is 0,\n  // the message is immediately made available for another streaming or\n  // non-streaming pull request. If the value is < 0 (an error), the stream will\n  // be aborted with status `INVALID_ARGUMENT`.\n  repeated int32 modify_deadline_seconds = 3;\n\n  // List of acknowledgement IDs whose deadline will be modified based on the\n  // corresponding element in `modify_deadline_seconds`. This field can be used\n  // to indicate that more time is needed to process a message by the\n  // subscriber, or to make the message available for redelivery if the\n  // processing was interrupted.\n  repeated string modify_deadline_ack_ids = 4;\n\n  // Required. The ack deadline to use for the stream. This must be provided in\n  // the first request on the stream, but it can also be updated on subsequent\n  // requests from client to server. The minimum deadline you can specify is 10\n  // seconds. The maximum deadline you can specify is 600 seconds (10 minutes).\n  int32 stream_ack_deadline_seconds = 5\n      [(google.api.field_behavior) = REQUIRED];\n\n  // A unique identifier that is used to distinguish client instances from each\n  // other. Only needs to be provided on the initial request. When a stream\n  // disconnects and reconnects for the same stream, the client_id should be set\n  // to the same value so that state associated with the old stream can be\n  // transferred to the new stream. The same client_id should not be used for\n  // different client instances.\n  string client_id = 6;\n\n  // Flow control settings for the maximum number of outstanding messages. When\n  // there are `max_outstanding_messages` or more currently sent to the\n  // streaming pull client that have not yet been acked or nacked, the server\n  // stops sending more messages. The sending of messages resumes once the\n  // number of outstanding messages is less than this value. If the value is\n  // <= 0, there is no limit to the number of outstanding messages. This\n  // property can only be set on the initial StreamingPullRequest. If it is set\n  // on a subsequent request, the stream will be aborted with status\n  // `INVALID_ARGUMENT`.\n  int64 max_outstanding_messages = 7;\n\n  // Flow control settings for the maximum number of outstanding bytes. When\n  // there are `max_outstanding_bytes` or more worth of messages currently sent\n  // to the streaming pull client that have not yet been acked or nacked, the\n  // server will stop sending more messages. The sending of messages resumes\n  // once the number of outstanding bytes is less than this value. If the value\n  // is <= 0, there is no limit to the number of outstanding bytes. This\n  // property can only be set on the initial StreamingPullRequest. If it is set\n  // on a subsequent request, the stream will be aborted with status\n  // `INVALID_ARGUMENT`.\n  int64 max_outstanding_bytes = 8;\n}\n\n// Response for the `StreamingPull` method. This response is used to stream\n// messages from the server to the client.\nmessage StreamingPullResponse {\n  // Received Pub/Sub messages. This will not be empty.\n  repeated ReceivedMessage received_messages = 1;\n}\n\n// Request for the `CreateSnapshot` method.\nmessage CreateSnapshotRequest {\n  // Required. User-provided name for this snapshot. If the name is not provided\n  // in the request, the server will assign a random name for this snapshot on\n  // the same project as the subscription. Note that for REST API requests, you\n  // must specify a name.  See the <a\n  // href=\"https://cloud.google.com/pubsub/docs/admin#resource_names\"> resource\n  // name rules</a>. Format is `projects/{project}/snapshots/{snap}`.\n  string name = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Snapshot\" }\n  ];\n\n  // Required. The subscription whose backlog the snapshot retains.\n  // Specifically, the created snapshot is guaranteed to retain:\n  //  (a) The existing backlog on the subscription. More precisely, this is\n  //      defined as the messages in the subscription's backlog that are\n  //      unacknowledged upon the successful completion of the\n  //      `CreateSnapshot` request; as well as:\n  //  (b) Any messages published to the subscription's topic following the\n  //      successful completion of the CreateSnapshot request.\n  // Format is `projects/{project}/subscriptions/{sub}`.\n  string subscription = 2 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n\n  // See <a href=\"https://cloud.google.com/pubsub/docs/labels\"> Creating and\n  // managing labels</a>.\n  map<string, string> labels = 3;\n}\n\n// Request for the UpdateSnapshot method.\nmessage UpdateSnapshotRequest {\n  // Required. The updated snapshot object.\n  Snapshot snapshot = 1 [(google.api.field_behavior) = REQUIRED];\n\n  // Required. Indicates which fields in the provided snapshot to update.\n  // Must be specified and non-empty.\n  google.protobuf.FieldMask update_mask = 2\n      [(google.api.field_behavior) = REQUIRED];\n}\n\n// A snapshot resource. Snapshots are used in\n// [Seek](https://cloud.google.com/pubsub/docs/replay-overview)\n// operations, which allow you to manage message acknowledgments in bulk. That\n// is, you can set the acknowledgment state of messages in an existing\n// subscription to the state captured by a snapshot.\nmessage Snapshot {\n  option (google.api.resource) = {\n    type: \"pubsub.googleapis.com/Snapshot\"\n    pattern: \"projects/{project}/snapshots/{snapshot}\"\n  };\n\n  // The name of the snapshot.\n  string name = 1;\n\n  // The name of the topic from which this snapshot is retaining messages.\n  string topic = 2 [\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Topic\" }\n  ];\n\n  // The snapshot is guaranteed to exist up until this time.\n  // A newly-created snapshot expires no later than 7 days from the time of its\n  // creation. Its exact lifetime is determined at creation by the existing\n  // backlog in the source subscription. Specifically, the lifetime of the\n  // snapshot is `7 days - (age of oldest unacked message in the subscription)`.\n  // For example, consider a subscription whose oldest unacked message is 3 days\n  // old. If a snapshot is created from this subscription, the snapshot -- which\n  // will always capture this 3-day-old backlog as long as the snapshot\n  // exists -- will expire in 4 days. The service will refuse to create a\n  // snapshot that would expire in less than 1 hour after creation.\n  google.protobuf.Timestamp expire_time = 3;\n\n  // See [Creating and managing labels]\n  // (https://cloud.google.com/pubsub/docs/labels).\n  map<string, string> labels = 4;\n}\n\n// Request for the GetSnapshot method.\nmessage GetSnapshotRequest {\n  // Required. The name of the snapshot to get.\n  // Format is `projects/{project}/snapshots/{snap}`.\n  string snapshot = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Snapshot\" }\n  ];\n}\n\n// Request for the `ListSnapshots` method.\nmessage ListSnapshotsRequest {\n  // Required. The name of the project in which to list snapshots.\n  // Format is `projects/{project-id}`.\n  string project = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"cloudresourcemanager.googleapis.com/Project\"\n    }\n  ];\n\n  // Maximum number of snapshots to return.\n  int32 page_size = 2;\n\n  // The value returned by the last `ListSnapshotsResponse`; indicates that this\n  // is a continuation of a prior `ListSnapshots` call, and that the system\n  // should return the next page of data.\n  string page_token = 3;\n}\n\n// Response for the `ListSnapshots` method.\nmessage ListSnapshotsResponse {\n  // The resulting snapshots.\n  repeated Snapshot snapshots = 1;\n\n  // If not empty, indicates that there may be more snapshot that match the\n  // request; this value should be passed in a new `ListSnapshotsRequest`.\n  string next_page_token = 2;\n}\n\n// Request for the `DeleteSnapshot` method.\nmessage DeleteSnapshotRequest {\n  // Required. The name of the snapshot to delete.\n  // Format is `projects/{project}/snapshots/{snap}`.\n  string snapshot = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Snapshot\" }\n  ];\n}\n\n// Request for the `Seek` method.\nmessage SeekRequest {\n  // Required. The subscription to affect.\n  string subscription = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Subscription\"\n    }\n  ];\n\n  oneof target {\n    // The time to seek to.\n    // Messages retained in the subscription that were published before this\n    // time are marked as acknowledged, and messages retained in the\n    // subscription that were published after this time are marked as\n    // unacknowledged. Note that this operation affects only those messages\n    // retained in the subscription (configured by the combination of\n    // `message_retention_duration` and `retain_acked_messages`). For example,\n    // if `time` corresponds to a point before the message retention\n    // window (or to a point before the system's notion of the subscription\n    // creation time), only retained messages will be marked as unacknowledged,\n    // and already-expunged messages will not be restored.\n    google.protobuf.Timestamp time = 2;\n\n    // The snapshot to seek to. The snapshot's topic must be the same as that of\n    // the provided subscription.\n    // Format is `projects/{project}/snapshots/{snap}`.\n    string snapshot = 3 [(google.api.resource_reference) = {\n      type: \"pubsub.googleapis.com/Snapshot\"\n    }];\n  }\n}\n\n// Response for the `Seek` method (this response is empty).\nmessage SeekResponse {}\n"
  },
  {
    "path": "examples/proto/googleapis/google/pubsub/v1/schema.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.pubsub.v1;\n\nimport \"google/api/annotations.proto\";\nimport \"google/api/client.proto\";\nimport \"google/api/field_behavior.proto\";\nimport \"google/api/resource.proto\";\nimport \"google/protobuf/empty.proto\";\n\noption cc_enable_arenas = true;\noption csharp_namespace = \"Google.Cloud.PubSub.V1\";\noption go_package = \"google.golang.org/genproto/googleapis/pubsub/v1;pubsub\";\noption java_multiple_files = true;\noption java_outer_classname = \"SchemaProto\";\noption java_package = \"com.google.pubsub.v1\";\noption php_namespace = \"Google\\\\Cloud\\\\PubSub\\\\V1\";\noption ruby_package = \"Google::Cloud::PubSub::V1\";\n\n// Service for doing schema-related operations.\n//\n// EXPERIMENTAL: The Schema service is in development and may not work yet.\n\nservice SchemaService {\n  option (google.api.default_host) = \"pubsub.googleapis.com\";\n  option (google.api.oauth_scopes) =\n      \"https://www.googleapis.com/auth/cloud-platform,\"\n      \"https://www.googleapis.com/auth/pubsub\";\n\n  // Creates a schema.\n  rpc CreateSchema(CreateSchemaRequest) returns (Schema) {\n    option (google.api.http) = {\n      post: \"/v1/{parent=projects/*}/schemas\"\n      body: \"schema\"\n    };\n    option (google.api.method_signature) = \"parent,schema,schema_id\";\n  }\n\n  // Gets a schema.\n  rpc GetSchema(GetSchemaRequest) returns (Schema) {\n    option (google.api.http) = {\n      get: \"/v1/{name=projects/*/schemas/*}\"\n    };\n    option (google.api.method_signature) = \"name\";\n  }\n\n  // Lists schemas in a project.\n  rpc ListSchemas(ListSchemasRequest) returns (ListSchemasResponse) {\n    option (google.api.http) = {\n      get: \"/v1/{parent=projects/*}/schemas\"\n    };\n    option (google.api.method_signature) = \"parent\";\n  }\n\n  // Deletes a schema.\n  rpc DeleteSchema(DeleteSchemaRequest) returns (google.protobuf.Empty) {\n    option (google.api.http) = {\n      delete: \"/v1/{name=projects/*/schemas/*}\"\n    };\n    option (google.api.method_signature) = \"name\";\n  }\n\n  // Validates a schema.\n  rpc ValidateSchema(ValidateSchemaRequest) returns (ValidateSchemaResponse) {\n    option (google.api.http) = {\n      post: \"/v1/{parent=projects/*}/schemas:validate\"\n      body: \"*\"\n    };\n    option (google.api.method_signature) = \"parent,schema\";\n  }\n\n  // Validates a message against a schema.\n  rpc ValidateMessage(ValidateMessageRequest)\n      returns (ValidateMessageResponse) {\n    option (google.api.http) = {\n      post: \"/v1/{parent=projects/*}/schemas:validateMessage\"\n      body: \"*\"\n    };\n  }\n}\n\n// A schema resource.\nmessage Schema {\n  option (google.api.resource) = {\n    type: \"pubsub.googleapis.com/Schema\"\n    pattern: \"projects/{project}/schemas/{schema}\"\n  };\n\n  // Possible schema definition types.\n  enum Type {\n    // Default value. This value is unused.\n    TYPE_UNSPECIFIED = 0;\n\n    // A Protocol Buffer schema definition.\n    PROTOCOL_BUFFER = 1;\n\n    // An Avro schema definition.\n    AVRO = 2;\n  }\n\n  // Required. Name of the schema.\n  // Format is `projects/{project}/schemas/{schema}`.\n  string name = 1 [(google.api.field_behavior) = REQUIRED];\n\n  // The type of the schema definition.\n  Type type = 2;\n\n  // The definition of the schema. This should contain a string representing\n  // the full definition of the schema that is a valid schema definition of\n  // the type specified in `type`.\n  string definition = 3;\n}\n\n// Request for the CreateSchema method.\nmessage CreateSchemaRequest {\n  // Required. The name of the project in which to create the schema.\n  // Format is `projects/{project-id}`.\n  string parent = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      child_type: \"pubsub.googleapis.com/Schema\"\n    }\n  ];\n\n  // Required. The schema object to create.\n  //\n  // This schema's `name` parameter is ignored. The schema object returned\n  // by CreateSchema will have a `name` made using the given `parent` and\n  // `schema_id`.\n  Schema schema = 2 [(google.api.field_behavior) = REQUIRED];\n\n  // The ID to use for the schema, which will become the final component of\n  // the schema's resource name.\n  //\n  // See https://cloud.google.com/pubsub/docs/admin#resource_names for resource\n  // name constraints.\n  string schema_id = 3;\n}\n\n// View of Schema object fields to be returned by GetSchema and ListSchemas.\nenum SchemaView {\n  // The default / unset value.\n  // The API will default to the BASIC view.\n  SCHEMA_VIEW_UNSPECIFIED = 0;\n\n  // Include the name and type of the schema, but not the definition.\n  BASIC = 1;\n\n  // Include all Schema object fields.\n  FULL = 2;\n}\n\n// Request for the GetSchema method.\nmessage GetSchemaRequest {\n  // Required. The name of the schema to get.\n  // Format is `projects/{project}/schemas/{schema}`.\n  string name = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Schema\" }\n  ];\n\n  // The set of fields to return in the response. If not set, returns a Schema\n  // with `name` and `type`, but not `definition`. Set to `FULL` to retrieve all\n  // fields.\n  SchemaView view = 2;\n}\n\n// Request for the `ListSchemas` method.\nmessage ListSchemasRequest {\n  // Required. The name of the project in which to list schemas.\n  // Format is `projects/{project-id}`.\n  string parent = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"cloudresourcemanager.googleapis.com/Project\"\n    }\n  ];\n\n  // The set of Schema fields to return in the response. If not set, returns\n  // Schemas with `name` and `type`, but not `definition`. Set to `FULL` to\n  // retrieve all fields.\n  SchemaView view = 2;\n\n  // Maximum number of schemas to return.\n  int32 page_size = 3;\n\n  // The value returned by the last `ListSchemasResponse`; indicates that\n  // this is a continuation of a prior `ListSchemas` call, and that the\n  // system should return the next page of data.\n  string page_token = 4;\n}\n\n// Response for the `ListSchemas` method.\nmessage ListSchemasResponse {\n  // The resulting schemas.\n  repeated Schema schemas = 1;\n\n  // If not empty, indicates that there may be more schemas that match the\n  // request; this value should be passed in a new `ListSchemasRequest`.\n  string next_page_token = 2;\n}\n\n// Request for the `DeleteSchema` method.\nmessage DeleteSchemaRequest {\n  // Required. Name of the schema to delete.\n  // Format is `projects/{project}/schemas/{schema}`.\n  string name = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Schema\" }\n  ];\n}\n\n// Request for the `ValidateSchema` method.\nmessage ValidateSchemaRequest {\n  // Required. The name of the project in which to validate schemas.\n  // Format is `projects/{project-id}`.\n  string parent = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"cloudresourcemanager.googleapis.com/Project\"\n    }\n  ];\n\n  // Required. The schema object to validate.\n  Schema schema = 2 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Response for the `ValidateSchema` method.\nmessage ValidateSchemaResponse {}\n\n// Request for the `ValidateMessage` method.\nmessage ValidateMessageRequest {\n  // Required. The name of the project in which to validate schemas.\n  // Format is `projects/{project-id}`.\n  string parent = 1 [\n    (google.api.field_behavior) = REQUIRED,\n    (google.api.resource_reference) = {\n      type: \"cloudresourcemanager.googleapis.com/Project\"\n    }\n  ];\n\n  oneof schema_spec {\n    // Name of the schema against which to validate.\n    //\n    // Format is `projects/{project}/schemas/{schema}`.\n    string name = 2 [\n      (google.api.resource_reference) = { type: \"pubsub.googleapis.com/Schema\" }\n    ];\n\n    // Ad-hoc schema against which to validate\n    Schema schema = 3;\n  }\n\n  // Message to validate against the provided `schema_spec`.\n  bytes message = 4;\n\n  // The encoding expected for messages\n  Encoding encoding = 5;\n}\n\n// Response for the `ValidateMessage` method.\nmessage ValidateMessageResponse {}\n\n// Possible encoding types for messages.\nenum Encoding {\n  // Unspecified\n  ENCODING_UNSPECIFIED = 0;\n\n  // JSON encoding\n  JSON = 1;\n\n  // Binary encoding, as defined by the schema type. For some schema types,\n  // binary encoding may not be available.\n  BINARY = 2;\n}\n"
  },
  {
    "path": "examples/proto/helloworld/helloworld.proto",
    "content": "// Copyright 2015 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"io.grpc.examples.helloworld\";\noption java_outer_classname = \"HelloWorldProto\";\n\npackage helloworld;\n\n// The greeting service definition.\nservice Greeter {\n  // Sends a greeting\n  rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n// The request message containing the user's name.\nmessage HelloRequest {\n  string name = 1;\n}\n\n// The response message containing the greetings\nmessage HelloReply {\n  string message = 1;\n}\n"
  },
  {
    "path": "examples/proto/routeguide/route_guide.proto",
    "content": "// Copyright 2015 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"io.grpc.examples.routeguide\";\noption java_outer_classname = \"RouteGuideProto\";\n\npackage routeguide;\n\n// Interface exported by the server.\nservice RouteGuide {\n  // A simple RPC.\n  //\n  // Obtains the feature at a given position.\n  //\n  // A feature with an empty name is returned if there's no feature at the given\n  // position.\n  rpc GetFeature(Point) returns (Feature) {}\n\n  // A server-to-client streaming RPC.\n  //\n  // Obtains the Features available within the given Rectangle.  Results are\n  // streamed rather than returned at once (e.g. in a response message with a\n  // repeated field), as the rectangle may cover a large area and contain a\n  // huge number of features.\n  rpc ListFeatures(Rectangle) returns (stream Feature) {}\n\n  // A client-to-server streaming RPC.\n  //\n  // Accepts a stream of Points on a route being traversed, returning a\n  // RouteSummary when traversal is completed.\n  rpc RecordRoute(stream Point) returns (RouteSummary) {}\n\n  // A Bidirectional streaming RPC.\n  //\n  // Accepts a stream of RouteNotes sent while a route is being traversed,\n  // while receiving other RouteNotes (e.g. from other users).\n  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}\n}\n\n// Points are represented as latitude-longitude pairs in the E7 representation\n// (degrees multiplied by 10**7 and rounded to the nearest integer).\n// Latitudes should be in the range +/- 90 degrees and longitude should be in\n// the range +/- 180 degrees (inclusive).\nmessage Point {\n  int32 latitude = 1;\n  int32 longitude = 2;\n}\n\n// A latitude-longitude rectangle, represented as two diagonally opposite\n// points \"lo\" and \"hi\".\nmessage Rectangle {\n  // One corner of the rectangle.\n  Point lo = 1;\n\n  // The other corner of the rectangle.\n  Point hi = 2;\n}\n\n// A feature names something at a given point.\n//\n// If a feature could not be named, the name is empty.\nmessage Feature {\n  // The name of the feature.\n  string name = 1;\n\n  // The point where the feature is detected.\n  Point location = 2;\n}\n\n// A RouteNote is a message sent while at a given point.\nmessage RouteNote {\n  // The location from which the message is sent.\n  Point location = 1;\n\n  // The message to be sent.\n  string message = 2;\n}\n\n// A RouteSummary is received in response to a RecordRoute rpc.\n//\n// It contains the number of individual points received, the number of\n// detected features, and the total distance covered as the cumulative sum of\n// the distance between each point.\nmessage RouteSummary {\n  // The number of points received.\n  int32 point_count = 1;\n\n  // The number of known features passed while traversing the route.\n  int32 feature_count = 2;\n\n  // The distance covered in metres.\n  int32 distance = 3;\n\n  // The duration of the traversal in seconds.\n  int32 elapsed_time = 4;\n}\n"
  },
  {
    "path": "examples/proto/unaryecho/echo.proto",
    "content": "/*\n *\n * Copyright 2018 gRPC authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n syntax = \"proto3\";\n\n package grpc.examples.unaryecho;\n\n // EchoRequest is the request for echo.\n message EchoRequest {\n   string message = 1;\n }\n\n // EchoResponse is the response for echo.\n message EchoResponse {\n   string message = 1;\n }\n\n // Echo is the echo service.\n service Echo {\n   // UnaryEcho is unary echo.\n   rpc UnaryEcho(EchoRequest) returns (EchoResponse) {}\n }\n"
  },
  {
    "path": "examples/routeguide-tutorial.md",
    "content": "# gRPC Basics: Tonic\n\nThis tutorial, adapted from [grpc-go], provides a basic introduction to working with gRPC\nand Tonic. By walking through this example you'll learn how to:\n\n- Define a service in a `.proto` file.\n- Generate server and client code.\n- Write a simple client and server for your service.\n\nIt assumes you are familiar with [protocol buffers] and basic Rust. Note that the example in\nthis tutorial uses the proto3 version of the protocol buffers language, you can find out more in the\n[proto3 language guide][proto3].\n\n[grpc-go]: https://github.com/grpc/grpc-go/blob/master/examples/gotutorial.md\n[protocol buffers]: https://developers.google.com/protocol-buffers/docs/overview\n[proto3]: https://developers.google.com/protocol-buffers/docs/proto3\n\n## Why use gRPC?\n\nOur example is a simple route mapping application that lets clients get information about features\non their route, create a summary of their route, and exchange route information such as traffic\nupdates with the server and other clients.\n\nWith gRPC we can define our service once in a `.proto` file and implement clients and servers in\nany of gRPC's supported languages, which in turn can be run in environments ranging from servers\ninside Google to your own tablet - all the complexity of communication between different languages\nand environments is handled for you by gRPC. We also get all the advantages of working with\nprotocol buffers, including efficient serialization, a simple IDL, and easy interface updating.\n\n## Prerequisites\n\nTo run the sample code and walk through the tutorial, the only prerequisite is Rust itself.\n[rustup] is a convenient tool to install it, if you haven't already.\n\n[rustup]: https://rustup.rs\n\n## Running the example\n\nClone or download Tonic's repository:\n\n```shell\n$ git clone https://github.com/hyperium/tonic.git\n```\n\nChange your current directory to Tonic's repository root:\n```shell\n$ cd tonic\n```\n\nRun the server\n```shell\n$ cargo run --bin routeguide-server\n```\n\nIn a separate shell, run the client\n```shell\n$ cargo run --bin routeguide-client\n```\n\nYou should see some logging output flying past really quickly on both terminal windows. On the\nshell where you ran the client binary, you should see the output of the bidirectional streaming rpc,\nprinting 1 line per second:\n\n```\nNOTE = RouteNote { location: Some(Point { latitude: 409146139, longitude: -746188906 }), message: \"at 1.000319208s\" }\n```\n\nIf you scroll up you should see the output of the other 3 request types: simple rpc, server-side\nstreaming and client-side streaming.\n\n\n## Project setup\n\nWe will develop our example from scratch in a new crate:\n\n```shell\n$ cargo new routeguide\n$ cd routeguide\n```\n\n\n## Defining the service\n\nOur first step is to define the gRPC *service* and the method *request* and *response* types using\n[protocol buffers]. We will keep our `.proto` files in a directory in our crate's root.\nNote that Tonic does not really care where our `.proto` definitions live. We will see how to use\ndifferent [code generation configuration](#tonic-build) later in the tutorial.\n\n```shell\n$ mkdir proto && touch proto/route_guide.proto\n```\n\nYou can see the complete `.proto` file in\n[examples/proto/routeguide/route_guide.proto][routeguide-proto].\n\nTo define a service, you specify a named `service` in your `.proto` file:\n\n```proto\nservice RouteGuide {\n   ...\n}\n```\n\nThen you define `rpc` methods inside your service definition, specifying their request and response\ntypes. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide`\nservice:\n\n- A *simple RPC* where the client sends a request to the server and waits for a response to come\nback, just like a normal function call.\n```proto\n   // Obtains the feature at a given position.\n   rpc GetFeature(Point) returns (Feature) {}\n```\n\n- A *server-side streaming RPC* where the client sends a request to the server and gets a stream\nto read a sequence of messages back. The client reads from the returned stream until there are\nno more messages. As you can see in our example, you specify a server-side streaming method by\nplacing the `stream` keyword before the *response* type.\n```proto\n  // Obtains the Features available within the given Rectangle.  Results are\n  // streamed rather than returned at once (e.g. in a response message with a\n  // repeated field), as the rectangle may cover a large area and contain a\n  // huge number of features.\n  rpc ListFeatures(Rectangle) returns (stream Feature) {}\n```\n\n- A *client-side streaming RPC* where the client writes a sequence of messages and sends them to\nthe server. Once the client has finished writing the messages, it waits for the server to read them\nall and return its response. You specify a client-side streaming method by placing the `stream`\nkeyword before the *request* type.\n```proto\n  // Accepts a stream of Points on a route being traversed, returning a\n  // RouteSummary when traversal is completed.\n  rpc RecordRoute(stream Point) returns (RouteSummary) {}\n```\n\n- A *bidirectional streaming RPC* where both sides send a sequence of messages. The two streams\noperate independently, so clients and servers can read and write in whatever\norder they like: for example, the server could wait to receive all the client messages before\nwriting its responses, or it could alternately read a message then write a message, or some other\ncombination of reads and writes. The order of messages in each stream is preserved. You specify\nthis type of method by placing the `stream` keyword before both the request and the response.\n```proto\n  // Accepts a stream of RouteNotes sent while a route is being traversed,\n  // while receiving other RouteNotes (e.g. from other users).\n  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}\n```\n\nOur `.proto` file also contains protocol buffer message type definitions for all the request and\nresponse types used in our service methods - for example, here's the `Point` message type:\n```proto\n// Points are represented as latitude-longitude pairs in the E7 representation\n// (degrees multiplied by 10**7 and rounded to the nearest integer).\n// Latitudes should be in the range +/- 90 degrees and longitude should be in\n// the range +/- 180 degrees (inclusive).\nmessage Point {\n  int32 latitude = 1;\n  int32 longitude = 2;\n}\n```\n\n[routeguide-proto]: https://github.com/hyperium/tonic/blob/master/examples/proto/routeguide/route_guide.proto\n\n## Generating client and server code\n\nTonic can be configured to generate code as part cargo's normal build process. This is very\nconvenient because once we've set everything up, there is no extra step to keep the generated code\nand our `.proto` definitions in sync.\n\nBehind the scenes, Tonic uses [PROST!] to handle protocol buffer serialization and code\ngeneration.\n\nEdit `Cargo.toml` and add all the dependencies we'll need for this example:\n\n```toml\n[dependencies]\ntonic = \"*\"\nprost = \"0.14\"\ntokio = { version = \"1.0\", features = [\"rt-multi-thread\", \"macros\", \"sync\", \"time\"] }\ntokio-stream = \"0.1\"\n\nasync-stream = \"0.2\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0\"\nrand = \"0.8\"\n\n[build-dependencies]\ntonic-prost-build = \"*\"\n```\n\nCreate a `build.rs` file at the root of your crate:\n\n```rust\nfn main() {\n    tonic_prost_build::compile_protos(\"proto/route_guide.proto\")\n        .unwrap_or_else(|e| panic!(\"Failed to compile protos {:?}\", e));\n}\n```\n\n```shell\n$ cargo build\n```\n\nThat's it. The generated code contains:\n\n- Struct definitions for message types `Point`, `Rectangle`, `Feature`, `RouteNote`, `RouteSummary`.\n- A service trait we'll need to implement: `route_guide_server::RouteGuide`.\n- A client type we'll use to call the server: `route_guide_client::RouteGuideClient<T>`.\n\nIf your are curious as to where the generated files are, keep reading. The mystery will be revealed\nsoon! We can now move on to the fun part.\n\n[PROST!]: https://github.com/danburkert/prost\n\n## Creating the server\n\nFirst let's look at how we create a `RouteGuide` server. If you're only interested in creating gRPC\nclients, you can skip this section and go straight to [Creating the client](#client)\n(though you might find it interesting anyway!).\n\nThere are two parts to making our `RouteGuide` service do its job:\n\n- Implementing the service trait generated from our service definition.\n- Running a gRPC server to listen for requests from clients.\n\nYou can find our example `RouteGuide` server in\n[examples/src/routeguide/server.rs][routeguide-server].\n\n[routeguide-server]: https://github.com/hyperium/tonic/blob/master/examples/src/routeguide/server.rs\n\n### Implementing the RouteGuide server trait\n\nWe can start by defining a struct to represent our service, we can do this on `main.rs` for now:\n\n```rust\n#[derive(Debug)]\nstruct RouteGuideService;\n```\n\nNext, we need to implement the `route_guide_server::RouteGuide` trait that is generated in our build step.\nThe generated code is placed inside our target directory, in a location defined by the `OUT_DIR`\nenvironment variable that is set by cargo. For our example, this means you can find the generated\ncode in a path similar to `target/debug/build/routeguide/out/routeguide.rs`.\n\nYou can learn more about `build.rs` and the `OUT_DIR` environment variable in the [cargo book].\n\nWe can use Tonic's `include_proto` macro to bring the generated code into scope:\n\n```rust\npub mod routeguide {\n    tonic::include_proto!(\"routeguide\");\n}\n\nuse routeguide::route_guide_server::{RouteGuide, RouteGuideServer};\nuse routeguide::{Feature, Point, Rectangle, RouteNote, RouteSummary};\n```\n\n**Note**: The token passed to the `include_proto` macro (in our case \"routeguide\") is the name of\nthe package declared in our `.proto` file, not a filename, e.g \"routeguide.rs\".\n\nWith this in place, we can stub out our service implementation:\n\n```rust\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse tokio::sync::mpsc;\nuse tonic::{Request, Response, Status};\nuse tokio_stream::{wrappers::ReceiverStream, Stream};\n```\n\n```rust\n#[tonic::async_trait]\nimpl RouteGuide for RouteGuideService {\n    async fn get_feature(&self, _request: Request<Point>) -> Result<Response<Feature>, Status> {\n        unimplemented!()\n    }\n\n    type ListFeaturesStream = ReceiverStream<Result<Feature, Status>>;\n\n    async fn list_features(\n        &self,\n        _request: Request<Rectangle>,\n    ) -> Result<Response<Self::ListFeaturesStream>, Status> {\n        unimplemented!()\n    }\n\n    async fn record_route(\n        &self,\n        _request: Request<tonic::Streaming<Point>>,\n    ) -> Result<Response<RouteSummary>, Status> {\n        unimplemented!()\n    }\n\n    type RouteChatStream = Pin<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send  + 'static>>;\n\n    async fn route_chat(\n        &self,\n        _request: Request<tonic::Streaming<RouteNote>>,\n    ) -> Result<Response<Self::RouteChatStream>, Status> {\n        unimplemented!()\n    }\n}\n```\n\n**Note**: The `tonic::async_trait` attribute macro adds support for async functions in traits. It\nuses [async-trait] internally. You can learn more about `async fn` in traits in the [async book].\n\n\n[cargo book]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts\n[async-trait]: https://github.com/dtolnay/async-trait\n[async book]: https://rust-lang.github.io/async-book/07_workarounds/05_async_in_traits.html\n\n### Server state\nOur service needs access to an immutable list of features. When the server starts, we are going to\ndeserialize them from a json file and keep them around as our only piece of shared state:\n\n```rust\n#[derive(Debug)]\npub struct RouteGuideService {\n    features: Arc<Vec<Feature>>,\n}\n```\n\nCreate the json data file and a helper module to read and deserialize our features.\n\n```shell\n$ mkdir data && touch data/route_guide_db.json\n$ touch src/data.rs\n```\n\nYou can find our example json data in [examples/data/route_guide_db.json][route-guide-db] and\nthe corresponding `data` module to load and deserialize it in\n[examples/routeguide/data.rs][data-module].\n\n**Note:** If you are following along, you'll need to change the data file's path  from\n`examples/data/route_guide_db.json` to `data/route_guide_db.json`.\n\nLastly, we need implement two helper functions: `in_range` and `calc_distance`. We'll use them\nwhen performing feature lookups. You can find them in\n[examples/src/routeguide/server.rs][in-range-fn].\n\n[route-guide-db]: https://github.com/hyperium/tonic/blob/master/examples/data/route_guide_db.json\n[data-module]: https://github.com/hyperium/tonic/blob/master/examples/src/routeguide/data.rs\n[in-range-fn]: https://github.com/hyperium/tonic/blob/master/examples/src/routeguide/server.rs#L174\n\n#### Request and Response types\nAll our service methods receive a `tonic::Request<T>` and return a\n`Result<tonic::Response<T>, tonic::Status>`. The concrete type of `T` depends on how our methods\nare declared in our *service* `.proto` definition. It can be either:\n\n- A single value, e.g `Point`, `Rectangle`, or even a message type that includes a repeated field.\n- A stream of values, e.g. `impl Stream<Item = Result<Feature, tonic::Status>>`.\n\n#### Simple RPC\nLet's look at the simplest method first, `get_feature`, which just gets a `tonic::Request<Point>`\nfrom the client and tries to find a feature at the given `Point`. If no feature is found, it returns\nan empty one.\n\n```rust\nasync fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> {\n    for feature in &self.features[..] {\n        if feature.location.as_ref() == Some(request.get_ref()) {\n            return Ok(Response::new(feature.clone()));\n        }\n    }\n\n    Ok(Response::new(Feature::default()))\n}\n```\n\n\n#### Server-side streaming RPC\nNow let's look at one of our streaming RPCs. `list_features` is a server-side streaming RPC, so we\nneed to send back multiple `Feature`s to our client.\n\n```rust\ntype ListFeaturesStream = ReceiverStream<Result<Feature, Status>>;\n\nasync fn list_features(\n    &self,\n    request: Request<Rectangle>,\n) -> Result<Response<Self::ListFeaturesStream>, Status> {\n    let (tx, rx) = mpsc::channel(4);\n    let features = self.features.clone();\n\n    tokio::spawn(async move {\n        for feature in &features[..] {\n            if in_range(feature.location.as_ref().unwrap(), request.get_ref()) {\n                tx.send(Ok(feature.clone())).await.unwrap();\n            }\n        }\n    });\n\n    Ok(Response::new(ReceiverStream::new(rx)))\n}\n```\n\nLike `get_feature`, `list_features`'s input is a single message, a `Rectangle` in this\ncase. This time, however, we need to return a stream of values, rather than a single one.\nWe create a channel and spawn a new asynchronous task where we perform a lookup, sending\nthe features that satisfy our constraints into the channel.\n\nThe `Stream` half of the channel is returned to the caller, wrapped in a `tonic::Response`.\n\n\n#### Client-side streaming RPC\nNow let's look at something a little more complicated: the client-side streaming method\n`record_route`, where we get a stream of `Point`s from the client and return a single `RouteSummary`\nwith information about their trip. As you can see, this time the method receives a\n`tonic::Request<tonic::Streaming<Point>>`.\n\n```rust\nuse std::time::Instant;\nuse tokio_stream::StreamExt;\n```\n\n```rust\nasync fn record_route(\n    &self,\n    request: Request<tonic::Streaming<Point>>,\n) -> Result<Response<RouteSummary>, Status> {\n    let mut stream = request.into_inner();\n\n    let mut summary = RouteSummary::default();\n    let mut last_point = None;\n    let now = Instant::now();\n\n    while let Some(point) = stream.next().await {\n        let point = point?;\n        summary.point_count += 1;\n\n        for feature in &self.features[..] {\n            if feature.location.as_ref() == Some(&point) {\n                summary.feature_count += 1;\n            }\n        }\n\n        if let Some(ref last_point) = last_point {\n            summary.distance += calc_distance(last_point, &point);\n        }\n\n        last_point = Some(point);\n    }\n\n    summary.elapsed_time = now.elapsed().as_secs() as i32;\n\n    Ok(Response::new(summary))\n}\n```\n\n`record_route` is conceptually simple: we get a stream of `Points` and fold it into a `RouteSummary`.\nIn other words, we build a summary value as we process each `Point` in our stream, one by one.\nWhen there are no more `Points` in our stream, we return the `RouteSummary` wrapped in a\n`tonic::Response`.\n\n#### Bidirectional streaming RPC\nFinally, let's look at our bidirectional streaming RPC `route_chat`, which receives a stream\nof `RouteNote`s and returns  a stream of `RouteNote`s.\n\n```rust\nuse std::collections::HashMap;\n```\n\n```rust\ntype RouteChatStream =\n    Pin<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send  + 'static>>;\n\n\nasync fn route_chat(\n    &self,\n    request: Request<tonic::Streaming<RouteNote>>,\n) -> Result<Response<Self::RouteChatStream>, Status> {\n    let mut notes = HashMap::new();\n    let mut stream = request.into_inner();\n\n    let output = async_stream::try_stream! {\n        while let Some(note) = stream.next().await {\n            let note = note?;\n\n            let location = note.location.unwrap();\n\n            let location_notes = notes.entry(location).or_insert(vec![]);\n            location_notes.push(note);\n\n            for note in location_notes {\n                yield note.clone();\n            }\n        }\n    };\n\n    Ok(Response::new(Box::pin(output)\n        as Self::RouteChatStream))\n\n}\n```\n\n`route_chat` uses the [async-stream] crate to perform an asynchronous transformation\nfrom one (input) stream to another (output) stream. As the input is processed, each value is\ninserted into the notes map, yielding a clone of the original `RouteNote`. The resulting stream\nis then returned to the caller. Neat.\n\n**Note**: The funky `as` cast is needed due to a limitation in the rust compiler. This is expected\nto be fixed soon.\n\n[async-stream]: https://github.com/tokio-rs/async-stream\n\n### Starting the server\n\nOnce we've implemented all our methods, we also need to start up a gRPC server so that clients can\nactually use our service. This is how our `main` function looks like:\n\n```rust\nmod data;\nuse tonic::transport::Server;\n```\n\n```rust\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:10000\".parse().unwrap();\n\n    let route_guide = RouteGuideService {\n        features: Arc::new(data::load()),\n    };\n\n    let svc = RouteGuideServer::new(route_guide);\n\n    Server::builder().add_service(svc).serve(addr).await?;\n\n    Ok(())\n}\n```\n\nTo handle requests, `Tonic` uses [Tower] and [hyper] internally. What this means,\namong other things, is that we have a flexible and composable stack we can build on top of. We can,\nfor example, add an [interceptor][authentication-example] to process requests before they reach our service\nmethods.\n\n\n[Tower]: https://github.com/tower-rs\n[hyper]: https://github.com/hyperium/hyper\n[authentication-example]: https://github.com/hyperium/tonic/blob/master/examples/src/authentication/server.rs#L56\n\n<a name=\"client\"></a>\n## Creating the client\n\nIn this section, we'll look at creating a Tonic client for our `RouteGuide` service. You can see our\ncomplete example client code in [examples/src/routeguide/client.rs][routeguide-client].\n\nOur crate will have two binary targets: `routeguide-client` and `routeguide-server`. We need to\nedit our `Cargo.toml` accordingly:\n\n```toml\n[[bin]]\nname = \"routeguide-server\"\npath = \"src/server.rs\"\n\n[[bin]]\nname = \"routeguide-client\"\npath = \"src/client.rs\"\n```\n\nRename `main.rs` to `server.rs` and create a new file `client.rs`.\n\n```shell\n$ mv src/main.rs src/server.rs\n$ touch src/client.rs\n```\n\nTo call service methods, we first need to create a gRPC *client* to communicate with the server. Like in the server\ncase, we'll start by bringing the generated code into scope:\n\n```rust\npub mod routeguide {\n    tonic::include_proto!(\"routeguide\");\n}\n\nuse routeguide::route_guide_client::RouteGuideClient;\nuse routeguide::{Point, Rectangle, RouteNote};\n\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = RouteGuideClient::connect(\"http://[::1]:10000\").await?;\n\n     Ok(())\n}\n```\n\nSame as in the server implementation, we start by bringing our generated code into scope. We then\ncreate a client in our main function, passing the server's full URL to `RouteGuideClient::connect`.\nOur client is now ready to make service calls. Note that `client` is mutable, this is because it\nneeds to manage internal state.\n\n[routeguide-client]: https://github.com/hyperium/tonic/blob/master/examples/src/routeguide/client.rs\n\n\n### Calling service methods\nNow let's look at how we call our service methods. Note that in Tonic, RPCs are asynchronous,\nwhich means that RPC calls need to be `.await`ed.\n\n#### Simple RPC\nCalling the simple RPC `get_feature` is as straightforward as calling a local method:\n\n```rust\nuse tonic::Request;\n```\n\n```rust\nlet response = client\n    .get_feature(Request::new(Point {\n        latitude: 409146138,\n        longitude: -746188906,\n    }))\n    .await?;\n\nprintln!(\"RESPONSE = {:?}\", response);\n```\nWe call the `get_feature` client method, passing a single `Point` value wrapped in a\n`tonic::Request`. We get a `Result<tonic::Response<Feature>, tonic::Status>` back.\n\n#### Server-side streaming RPC\nHere's where we call the server-side streaming method `list_features`, which returns a stream of\ngeographical `Feature`s.\n\n```rust\nuse tonic::transport::Channel;\nuse std::error::Error;\n```\n\n```rust\nasync fn print_features(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {\n    let rectangle = Rectangle {\n        lo: Some(Point {\n            latitude: 400000000,\n            longitude: -750000000,\n        }),\n        hi: Some(Point {\n            latitude: 420000000,\n            longitude: -730000000,\n        }),\n    };\n\n    let mut stream = client\n        .list_features(Request::new(rectangle))\n        .await?\n        .into_inner();\n\n    while let Some(feature) = stream.message().await? {\n        println!(\"FEATURE = {:?}\", feature);\n    }\n\n    Ok(())\n}\n```\n\nAs in the simple RPC, we pass a single value request. However, instead of getting a\nsingle value back, we get a stream of `Features`.\n\nWe use the `message()` method from the `tonic::Streaming` struct to repeatedly read in the\nserver's responses to a response protocol buffer object (in this case a `Feature`) until there are\nno more messages left in the stream.\n\n#### Client-side streaming RPC\nThe client-side streaming method `record_route` takes a stream of `Point`s and returns a single\n`RouteSummary` value.\n\n```rust\nuse rand::rngs::ThreadRng;\nuse rand::Rng;\n```\n\n```rust\nasync fn run_record_route(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {\n    let mut rng = rand::rng();\n    let point_count: i32 = rng.random_range(2..100);\n\n    let mut points = vec![];\n    for _ in 0..=point_count {\n        points.push(random_point(&mut rng))\n    }\n\n    println!(\"Traversing {} points\", points.len());\n    let request = Request::new(tokio_stream::iter(points));\n\n    match client.record_route(request).await {\n        Ok(response) => println!(\"SUMMARY: {:?}\", response.into_inner()),\n        Err(e) => println!(\"something went wrong: {:?}\", e),\n    }\n\n    Ok(())\n}\n```\n\n```rust\nfn random_point(rng: &mut ThreadRng) -> Point {\n    let latitude = (rng.random_range(0..180) - 90) * 10_000_000;\n    let longitude = (rng.random_range(0..360) - 180) * 10_000_000;\n    Point {\n        latitude,\n        longitude,\n    }\n}\n```\n\nWe build a vector of a random number of `Point` values (between 2 and 100) and then convert\nit into a `Stream` using the `tokio_stream::iter` function. This is a cheap an easy way to get\na stream suitable for passing into our service method. The resulting stream is then wrapped in a\n`tonic::Request`.\n\n\n#### Bidirectional streaming RPC\n\nFinally, let's look at our bidirectional streaming RPC. The `route_chat` method takes a stream\nof `RouteNotes` and returns either another stream of `RouteNotes` or an error.\n\n```rust\nuse std::time::Duration;\nuse tokio::time;\n```\n\n```rust\nasync fn run_route_chat(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {\n    let start = time::Instant::now();\n\n    let outbound = async_stream::stream! {\n        let mut interval = time::interval(Duration::from_secs(1));\n\n        while let time = interval.tick().await {\n            let elapsed = time.duration_since(start);\n            let note = RouteNote {\n                location: Some(Point {\n                    latitude: 409146138 + elapsed.as_secs() as i32,\n                    longitude: -746188906,\n                }),\n                message: format!(\"at {:?}\", elapsed),\n            };\n\n            yield note;\n        }\n    };\n\n    let response = client.route_chat(Request::new(outbound)).await?;\n    let mut inbound = response.into_inner();\n\n    while let Some(note) = inbound.message().await? {\n        println!(\"NOTE = {:?}\", note);\n    }\n\n    Ok(())\n}\n```\nIn this case, we use the [async-stream] crate to generate our outbound stream, yielding\n`RouteNote` values in one second intervals. We then iterate over the stream returned by\nthe server, printing each value in the stream.\n\n## Try it out!\n\n### Run the server\n```shell\n$ cargo run --bin routeguide-server\n```\n\n### Run the client\n```shell\n$ cargo run --bin routeguide-client\n```\n\n## Appendix\n\n<a name=\"tonic-build\"></a>\n### tonic_prost_build configuration\n\nTonic's default code generation configuration is convenient for self contained examples and small\nprojects. However, there are some cases when we need a slightly different workflow. For example:\n\n- When building rust clients and servers in different crates.\n- When building a rust client or server (or both) as part of a larger, multi-language project.\n- When we want editor support for the generate code and our editor does not index the generated\nfiles in the default location.\n\nMore generally, whenever we want to keep our `.proto` definitions in a central place and generate\ncode for different crates or different languages, the default configuration is not enough.\n\nLuckily, `tonic_prost_build` can be configured to fit whatever workflow we need. Here are just two\npossibilities:\n\n1)  We can keep our `.proto` definitions in a separate crate and generate our code on demand, as\nopposed to at build time, placing the resulting modules wherever we need them.\n\n`main.rs`\n\n```rust\nfn main() {\n    tonic_prost_build::configure()\n        .build_client(false)\n        .out_dir(\"another_crate/src/pb\")\n        .compile_protos(&[\"path/my_proto.proto\"], &[\"path\"])\n        .expect(\"failed to compile protos\");\n}\n```\n\nOn `cargo run`, this will generate code for the server only, and place the resulting file in\n`another_crate/src/pb`.\n\n2) Similarly, we could also keep the `.proto` definitions in a separate crate and then use that\ncrate as a direct dependency wherever we need it.\n"
  },
  {
    "path": "examples/src/authentication/client.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, echo_client::EchoClient};\nuse tonic::{Request, metadata::MetadataValue, transport::Channel};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let channel = Channel::from_static(\"http://[::1]:50051\").connect().await?;\n\n    let token: MetadataValue<_> = \"Bearer some-auth-token\".parse()?;\n\n    let mut client = EchoClient::with_interceptor(channel, move |mut req: Request<()>| {\n        req.metadata_mut().insert(\"authorization\", token.clone());\n        Ok(req)\n    });\n\n    let request = tonic::Request::new(EchoRequest {\n        message: \"hello\".into(),\n    });\n\n    let response = client.unary_echo(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/authentication/server.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, EchoResponse};\nuse tonic::{Request, Response, Status, metadata::MetadataValue, transport::Server};\n\ntype EchoResult<T> = Result<Response<T>, Status>;\n\n#[derive(Default)]\npub struct EchoServer {}\n\n#[tonic::async_trait]\nimpl pb::echo_server::Echo for EchoServer {\n    async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        let message = request.into_inner().message;\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let server = EchoServer::default();\n\n    let svc = pb::echo_server::EchoServer::with_interceptor(server, check_auth);\n\n    Server::builder().add_service(svc).serve(addr).await?;\n\n    Ok(())\n}\n\nfn check_auth(req: Request<()>) -> Result<Request<()>, Status> {\n    let token: MetadataValue<_> = \"Bearer some-secret-token\".parse().unwrap();\n\n    match req.metadata().get(\"authorization\") {\n        Some(t) if token == t => Ok(req),\n        _ => Err(Status::unauthenticated(\"No valid auth token\")),\n    }\n}\n"
  },
  {
    "path": "examples/src/autoreload/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    let server = Server::builder().add_service(GreeterServer::new(greeter));\n\n    match listenfd::ListenFd::from_env().take_tcp_listener(0)? {\n        Some(listener) => {\n            listener.set_nonblocking(true)?;\n            let listener = tokio_stream::wrappers::TcpListenerStream::new(\n                tokio::net::TcpListener::from_std(listener)?,\n            );\n\n            server.serve_with_incoming(listener).await?;\n        }\n        None => {\n            server.serve(addr).await?;\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/blocking/client.rs",
    "content": "use tokio::runtime::{Builder, Runtime};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\nuse hello_world::{HelloReply, HelloRequest, greeter_client::GreeterClient};\n\ntype StdError = Box<dyn std::error::Error + Send + Sync + 'static>;\ntype Result<T, E = StdError> = ::std::result::Result<T, E>;\n\n// The order of the fields in this struct is important. They must be ordered\n// such that when `BlockingClient` is dropped the client is dropped\n// before the runtime. Not doing this will result in a deadlock when dropped.\n// Rust drops struct fields in declaration order.\nstruct BlockingClient {\n    client: GreeterClient<tonic::transport::Channel>,\n    rt: Runtime,\n}\n\nimpl BlockingClient {\n    pub fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>\n    where\n        D: TryInto<tonic::transport::Endpoint>,\n        D::Error: Into<StdError>,\n    {\n        let rt = Builder::new_multi_thread().enable_all().build().unwrap();\n        let client = rt.block_on(GreeterClient::connect(dst))?;\n\n        Ok(Self { client, rt })\n    }\n\n    pub fn say_hello(\n        &mut self,\n        request: impl tonic::IntoRequest<HelloRequest>,\n    ) -> Result<tonic::Response<HelloReply>, tonic::Status> {\n        self.rt.block_on(self.client.say_hello(request))\n    }\n}\n\nfn main() -> Result<()> {\n    let mut client = BlockingClient::connect(\"http://[::1]:50051\")?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request)?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/blocking/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\nuse tokio::runtime::Runtime;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Debug, Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request: {:?}\", request);\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n\n        Ok(Response::new(reply))\n    }\n}\n\nfn main() {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    let rt = Runtime::new().expect(\"failed to obtain a new RunTime object\");\n    let server_future = Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr);\n    rt.block_on(server_future)\n        .expect(\"failed to successfully run the future on RunTime\");\n}\n"
  },
  {
    "path": "examples/src/cancellation/client.rs",
    "content": "use hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\n\nuse tokio::time::{Duration, timeout};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    // Cancelling the request by dropping the request future after 1 second\n    let response = match timeout(Duration::from_secs(1), client.say_hello(request)).await {\n        Ok(response) => response?,\n        Err(_) => {\n            println!(\"Cancelled request after 1s\");\n            return Ok(());\n        }\n    };\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/cancellation/server.rs",
    "content": "use std::future::Future;\n\nuse tokio_util::sync::CancellationToken;\nuse tonic::{Request, Response, Status, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\nuse tokio::select;\nuse tokio::time::Duration;\nuse tokio::time::sleep;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        let remote_addr = request.remote_addr();\n        let request_future = async move {\n            println!(\"Got a request from {:?}\", request.remote_addr());\n\n            // Take a long time to complete request for the client to cancel early\n            sleep(Duration::from_secs(10)).await;\n\n            let reply = hello_world::HelloReply {\n                message: format!(\"Hello {}!\", request.into_inner().name),\n            };\n\n            Ok(Response::new(reply))\n        };\n        let cancellation_future = async move {\n            println!(\"Request from {remote_addr:?} cancelled by client\");\n            // If this future is executed it means the request future was dropped,\n            // so it doesn't actually matter what is returned here\n            Err(Status::cancelled(\"Request cancelled by client\"))\n        };\n        with_cancellation_handler(request_future, cancellation_future).await\n    }\n}\n\nasync fn with_cancellation_handler<FRequest, FCancellation>(\n    request_future: FRequest,\n    cancellation_future: FCancellation,\n) -> Result<Response<HelloReply>, Status>\nwhere\n    FRequest: Future<Output = Result<Response<HelloReply>, Status>> + Send + 'static,\n    FCancellation: Future<Output = Result<Response<HelloReply>, Status>> + Send + 'static,\n{\n    let token = CancellationToken::new();\n    // Will call token.cancel() when the future is dropped, such as when the client cancels the request\n    let _drop_guard = token.clone().drop_guard();\n    let select_task = tokio::spawn(async move {\n        // Can select on token cancellation on any cancellable future while handling the request,\n        // allowing for custom cleanup code or monitoring\n        select! {\n            res = request_future => res,\n            _ = token.cancelled() => cancellation_future.await,\n        }\n    });\n\n    select_task.await.unwrap()\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/codec_buffers/client.rs",
    "content": "//! A HelloWorld example that uses a custom codec instead of the default Prost codec.\n//!\n//! Generated code is the output of codegen as defined in the `examples/build.rs` file.\n//! The generation is the one with .codec_path(\"crate::common::SmallBufferCodec\")\n//! The generated code assumes that a module `crate::common` exists which defines\n//! `SmallBufferCodec`, and `SmallBufferCodec` must have a Default implementation.\n\npub mod common;\n\npub mod small_buf {\n    include!(concat!(env!(\"OUT_DIR\"), \"/smallbuf/helloworld.rs\"));\n}\nuse small_buf::greeter_client::GreeterClient;\n\nuse crate::small_buf::HelloRequest;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/codec_buffers/common.rs",
    "content": "//! This module defines a common encoder with small buffers. This is useful\n//! when you have many concurrent RPC's, and not a huge volume of data per\n//! rpc normally.\n//!\n//! Note that you can customize your codecs per call to the code generator's\n//! compile function. This lets you group services by their codec needs.\n//!\n//! While this codec demonstrates customizing the built-in Prost codec, you\n//! can use this to implement other codecs as well, as long as they have a\n//! Default implementation.\n\nuse std::marker::PhantomData;\n\nuse prost::Message;\nuse tonic::codec::{BufferSettings, Codec};\nuse tonic_prost::ProstCodec;\n\n#[derive(Debug, Clone, Copy, Default)]\npub struct SmallBufferCodec<T, U>(PhantomData<(T, U)>);\n\nimpl<T, U> Codec for SmallBufferCodec<T, U>\nwhere\n    T: Message + Send + 'static,\n    U: Message + Default + Send + 'static,\n{\n    type Encode = T;\n    type Decode = U;\n\n    type Encoder = <ProstCodec<T, U> as Codec>::Encoder;\n    type Decoder = <ProstCodec<T, U> as Codec>::Decoder;\n\n    fn encoder(&mut self) -> Self::Encoder {\n        // Here, we will just customize the prost codec's internal buffer settings.\n        // You can of course implement a complete Codec, Encoder, and Decoder if\n        // you wish!\n        ProstCodec::<T, U>::raw_encoder(BufferSettings::new(512, 4096))\n    }\n\n    fn decoder(&mut self) -> Self::Decoder {\n        ProstCodec::<T, U>::raw_decoder(BufferSettings::new(512, 4096))\n    }\n}\n"
  },
  {
    "path": "examples/src/codec_buffers/server.rs",
    "content": "//! A HelloWorld example that uses a custom codec instead of the default Prost codec.\n//!\n//! Generated code is the output of codegen as defined in the `examples/build.rs` file.\n//! The generation is the one with .codec_path(\"crate::common::SmallBufferCodec\")\n//! The generated code assumes that a module `crate::common` exists which defines\n//! `SmallBufferCodec`, and `SmallBufferCodec` must have a Default implementation.\n\nuse tonic::{Request, Response, Status, transport::Server};\n\npub mod common;\n\npub mod small_buf {\n    include!(concat!(env!(\"OUT_DIR\"), \"/smallbuf/helloworld.rs\"));\n}\nuse small_buf::{\n    HelloReply, HelloRequest,\n    greeter_server::{Greeter, GreeterServer},\n};\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/compression/client.rs",
    "content": "use hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\nuse tonic::codec::CompressionEncoding;\nuse tonic::transport::Channel;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let channel = Channel::builder(\"http://[::1]:50051\".parse().unwrap())\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client = GreeterClient::new(channel)\n        .send_compressed(CompressionEncoding::Gzip)\n        .accept_compressed(CompressionEncoding::Gzip);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    dbg!(response);\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/compression/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\nuse tonic::codec::CompressionEncoding;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    let service = GreeterServer::new(greeter)\n        .send_compressed(CompressionEncoding::Gzip)\n        .accept_compressed(CompressionEncoding::Gzip);\n\n    Server::builder().add_service(service).serve(addr).await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/dynamic/server.rs",
    "content": "use std::env;\nuse tonic::{Request, Response, Status, service::RoutesBuilder, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\nuse echo::echo_server::{Echo, EchoServer};\nuse echo::{EchoRequest, EchoResponse};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\npub mod echo {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\ntype EchoResult<T> = Result<Response<T>, Status>;\n\n#[derive(Default)]\npub struct MyEcho {}\n\n#[tonic::async_trait]\nimpl Echo for MyEcho {\n    async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        println!(\"Got an echo request from {:?}\", request.remote_addr());\n\n        let message = format!(\"you said: {}\", request.into_inner().message);\n\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n\nfn init_echo(args: &[String], builder: &mut RoutesBuilder) {\n    let enabled = args.iter().any(|arg| arg.as_str() == \"echo\");\n    if enabled {\n        println!(\"Adding Echo service...\");\n        let svc = EchoServer::new(MyEcho::default());\n        builder.add_service(svc);\n    }\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a greet request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\nfn init_greeter(args: &[String], builder: &mut RoutesBuilder) {\n    let enabled = args.iter().any(|arg| arg.as_str() == \"greeter\");\n\n    if enabled {\n        println!(\"Adding Greeter service...\");\n        let svc = GreeterServer::new(MyGreeter::default());\n        builder.add_service(svc);\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let args: Vec<String> = env::args().collect();\n    let mut routes_builder = RoutesBuilder::default();\n    init_greeter(&args, &mut routes_builder);\n    init_echo(&args, &mut routes_builder);\n\n    let addr = \"[::1]:50051\".parse().unwrap();\n\n    println!(\"Grpc server listening on {addr}\");\n\n    Server::builder()\n        .add_routes(routes_builder.routes())\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/dynamic_load_balance/client.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, echo_client::EchoClient};\nuse tonic::transport::Channel;\nuse tonic::transport::Endpoint;\nuse tonic::transport::channel::Change;\n\nuse std::sync::Arc;\n\nuse std::sync::atomic::{AtomicBool, Ordering::SeqCst};\nuse tokio::time::timeout;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let e1 = Endpoint::from_static(\"http://[::1]:50051\");\n    let e2 = Endpoint::from_static(\"http://[::1]:50052\");\n\n    let (channel, rx) = Channel::balance_channel(10);\n    let mut client = EchoClient::new(channel);\n\n    let done = Arc::new(AtomicBool::new(false));\n    let demo_done = done.clone();\n    tokio::spawn(async move {\n        tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;\n        println!(\"Added first endpoint\");\n        let change = Change::Insert(\"1\", e1);\n        let res = rx.send(change).await;\n        println!(\"{res:?}\");\n        tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;\n        println!(\"Added second endpoint\");\n        let change = Change::Insert(\"2\", e2);\n        let res = rx.send(change).await;\n        println!(\"{res:?}\");\n        tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;\n        println!(\"Removed first endpoint\");\n        let change = Change::Remove(\"1\");\n        let res = rx.send(change).await;\n        println!(\"{res:?}\");\n\n        tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;\n        println!(\"Removed second endpoint\");\n        let change = Change::Remove(\"2\");\n        let res = rx.send(change).await;\n        println!(\"{res:?}\");\n\n        tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;\n        println!(\"Added third endpoint\");\n        let e3 = Endpoint::from_static(\"http://[::1]:50051\");\n        let change = Change::Insert(\"3\", e3);\n        let res = rx.send(change).await;\n        println!(\"{res:?}\");\n\n        tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;\n        println!(\"Removed third endpoint\");\n        let change = Change::Remove(\"3\");\n        let res = rx.send(change).await;\n        println!(\"{res:?}\");\n        demo_done.swap(true, SeqCst);\n    });\n\n    while !done.load(SeqCst) {\n        tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;\n        let request = tonic::Request::new(EchoRequest {\n            message: \"hello\".into(),\n        });\n\n        let rx = client.unary_echo(request);\n        if let Ok(resp) = timeout(tokio::time::Duration::from_secs(10), rx).await {\n            println!(\"RESPONSE={resp:?}\");\n        } else {\n            println!(\"did not receive value within 10 secs\");\n        }\n    }\n\n    println!(\"... Bye\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/dynamic_load_balance/server.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse std::net::SocketAddr;\nuse tokio::sync::mpsc;\nuse tonic::{Request, Response, Status, transport::Server};\n\nuse pb::{EchoRequest, EchoResponse};\n\ntype EchoResult<T> = Result<Response<T>, Status>;\n\n#[derive(Debug)]\npub struct EchoServer {\n    addr: SocketAddr,\n}\n\n#[tonic::async_trait]\nimpl pb::echo_server::Echo for EchoServer {\n    async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        let message = format!(\"{} (from {})\", request.into_inner().message, self.addr);\n\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addrs = [\"[::1]:50051\", \"[::1]:50052\"];\n\n    let (tx, mut rx) = mpsc::unbounded_channel();\n\n    for addr in &addrs {\n        let addr = addr.parse()?;\n        let tx = tx.clone();\n\n        let server = EchoServer { addr };\n        let serve = Server::builder()\n            .add_service(pb::echo_server::EchoServer::new(server))\n            .serve(addr);\n\n        tokio::spawn(async move {\n            if let Err(e) = serve.await {\n                eprintln!(\"Error = {e:?}\");\n            }\n\n            tx.send(()).unwrap();\n        });\n    }\n\n    rx.recv().await;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/gcp/README.md",
    "content": "# Google Cloud Pubsub example\n\nThis example will attempt to fetch a list of topics using the google\ngRPC protobuf specification. This will use an OAuth token and TLS to\nfetch the list of topics.\n\nFirst, you must generate a access token via the [OAuth playground]. From here\nselect the `Cloud Pub/Sub API v1` and its urls as the scope. This will start\nthe OAuth flow. Then you must hit the `Exchange authorization code for tokens`\nbutton to generate an `access_token` which will show up in the HTTP response\nto the right under the `access_token` field in the response json.\n\nOnce, you have this token you must fetch your GCP project id which can be found\nfrom the main page on the dashboard. When you have both of these items you can\nrun the example like so:\n\n```shell\nGCP_AUTH_TOKEN=\"<access-token>\" cargo run --bin gcp-client -- <project-id>\n```\n\n[OAuth playground]: https://developers.google.com/oauthplayground/\n"
  },
  {
    "path": "examples/src/gcp/client.rs",
    "content": "pub mod api {\n    tonic::include_proto!(\"google.pubsub.v1\");\n}\n\nuse api::{ListTopicsRequest, publisher_client::PublisherClient};\nuse tonic::{\n    Request,\n    metadata::MetadataValue,\n    transport::{Certificate, Channel, ClientTlsConfig},\n};\n\nconst ENDPOINT: &str = \"https://pubsub.googleapis.com\";\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let token = std::env::var(\"GCP_AUTH_TOKEN\").map_err(|_| {\n        \"Pass a valid 0Auth bearer token via `GCP_AUTH_TOKEN` environment variable.\".to_string()\n    })?;\n\n    let project = std::env::args()\n        .nth(1)\n        .ok_or_else(|| \"Expected a project name as the first argument.\".to_string())?;\n\n    let bearer_token = format!(\"Bearer {token}\");\n    let header_value: MetadataValue<_> = bearer_token.parse()?;\n\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let certs = std::fs::read_to_string(data_dir.join(\"gcp/roots.pem\"))?;\n\n    let tls_config = ClientTlsConfig::new()\n        .ca_certificate(Certificate::from_pem(certs))\n        .domain_name(\"pubsub.googleapis.com\");\n\n    let channel = Channel::from_static(ENDPOINT)\n        .tls_config(tls_config)?\n        .connect()\n        .await?;\n\n    let mut service = PublisherClient::with_interceptor(channel, move |mut req: Request<()>| {\n        req.metadata_mut()\n            .insert(\"authorization\", header_value.clone());\n        Ok(req)\n    });\n\n    let response = service\n        .list_topics(Request::new(ListTopicsRequest {\n            project: format!(\"projects/{project}\"),\n            page_size: 10,\n            ..Default::default()\n        }))\n        .await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/grpc-web/client.rs",
    "content": "use hello_world::{HelloRequest, greeter_client::GreeterClient};\nuse hyper_util::rt::TokioExecutor;\nuse tonic_web::GrpcWebClientLayer;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    // Must use hyper directly...\n    let client = hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build_http();\n\n    let svc = tower::ServiceBuilder::new()\n        .layer(GrpcWebClientLayer::new())\n        .service(client);\n\n    let mut client = GreeterClient::with_origin(svc, \"http://127.0.0.1:3000\".try_into()?);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/grpc-web/server.rs",
    "content": "use tonic::{Request, Response, Status, service::LayerExt as _, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    tracing_subscriber::fmt::init();\n\n    let addr = \"127.0.0.1:3000\".parse().unwrap();\n\n    let greeter = MyGreeter::default();\n    let greeter = tower::ServiceBuilder::new()\n        .layer(tower_http::cors::CorsLayer::new())\n        .layer(tonic_web::GrpcWebLayer::new())\n        .into_inner()\n        .named_layer(GreeterServer::new(greeter));\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder()\n        // GrpcWeb is over http1 so we must enable it.\n        .accept_http1(true)\n        .add_service(greeter)\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/h2c/client.rs",
    "content": "use hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\nuse http::Uri;\nuse hyper_util::client::legacy::Client;\nuse hyper_util::rt::TokioExecutor;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let origin = Uri::from_static(\"http://[::1]:50051\");\n    let h2c_client = h2c::H2cChannel {\n        client: Client::builder(TokioExecutor::new()).build_http(),\n    };\n\n    let mut client = GreeterClient::with_origin(h2c_client, origin);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n\nmod h2c {\n    use std::{\n        pin::Pin,\n        task::{Context, Poll},\n    };\n\n    use hyper::body::Incoming;\n    use hyper_util::{\n        client::legacy::{Client, connect::HttpConnector},\n        rt::TokioExecutor,\n    };\n    use tonic::body::Body;\n    use tower::Service;\n\n    pub struct H2cChannel {\n        pub client: Client<HttpConnector, Body>,\n    }\n\n    impl Service<http::Request<Body>> for H2cChannel {\n        type Response = http::Response<Incoming>;\n        type Error = hyper::Error;\n        type Future =\n            Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;\n\n        fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n\n        fn call(&mut self, request: http::Request<Body>) -> Self::Future {\n            let client = self.client.clone();\n\n            Box::pin(async move {\n                let origin = request.uri();\n\n                let h2c_req = hyper::Request::builder()\n                    .uri(origin)\n                    .header(http::header::UPGRADE, \"h2c\")\n                    .body(Body::default())\n                    .unwrap();\n\n                let res = client.request(h2c_req).await.unwrap();\n\n                if res.status() != http::StatusCode::SWITCHING_PROTOCOLS {\n                    panic!(\"Our server didn't upgrade: {}\", res.status());\n                }\n\n                let upgraded_io = hyper::upgrade::on(res).await.unwrap();\n\n                // In an ideal world you would somehow cache this connection\n                let (mut h2_client, conn) =\n                    hyper::client::conn::http2::Builder::new(TokioExecutor::new())\n                        .handshake(upgraded_io)\n                        .await\n                        .unwrap();\n                tokio::spawn(conn);\n\n                h2_client.send_request(request).await\n            })\n        }\n    }\n}\n"
  },
  {
    "path": "examples/src/h2c/server.rs",
    "content": "use std::net::SocketAddr;\n\nuse hyper_util::rt::{TokioExecutor, TokioIo};\nuse hyper_util::server::conn::auto::Builder;\nuse hyper_util::service::TowerToHyperService;\nuse tokio::net::TcpListener;\nuse tonic::{Request, Response, Status, service::Routes};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr: SocketAddr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    let incoming = TcpListener::bind(addr).await?;\n    let svc = Routes::new(GreeterServer::new(greeter)).prepare();\n\n    let h2c = h2c::H2c { s: svc };\n\n    loop {\n        match incoming.accept().await {\n            Ok((io, _)) => {\n                let router = h2c.clone();\n                tokio::spawn(async move {\n                    let builder = Builder::new(TokioExecutor::new());\n                    let conn = builder.serve_connection_with_upgrades(\n                        TokioIo::new(io),\n                        TowerToHyperService::new(router),\n                    );\n                    let _ = conn.await;\n                });\n            }\n            Err(e) => {\n                eprintln!(\"Error accepting connection: {e}\");\n            }\n        }\n    }\n}\n\nmod h2c {\n    use std::pin::Pin;\n\n    use http::{Request, Response};\n    use hyper::body::Incoming;\n    use hyper_util::{rt::TokioExecutor, service::TowerToHyperService};\n    use tonic::body::Body;\n    use tower::{Service, ServiceExt};\n\n    #[derive(Clone)]\n    pub struct H2c<S> {\n        pub s: S,\n    }\n\n    type BoxError = Box<dyn std::error::Error + Send + Sync>;\n\n    impl<S> Service<Request<Incoming>> for H2c<S>\n    where\n        S: Service<Request<Body>, Response = Response<Body>> + Clone + Send + 'static,\n        S::Future: Send,\n        S::Error: Into<BoxError> + 'static,\n    {\n        type Response = hyper::Response<Body>;\n        type Error = hyper::Error;\n        type Future =\n            Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;\n\n        fn poll_ready(\n            &mut self,\n            _: &mut std::task::Context<'_>,\n        ) -> std::task::Poll<Result<(), Self::Error>> {\n            std::task::Poll::Ready(Ok(()))\n        }\n\n        fn call(&mut self, req: hyper::Request<Incoming>) -> Self::Future {\n            let mut req = req.map(Body::new);\n            let svc = self\n                .s\n                .clone()\n                .map_request(|req: Request<_>| req.map(Body::new));\n            Box::pin(async move {\n                tokio::spawn(async move {\n                    let upgraded_io = hyper::upgrade::on(&mut req).await.unwrap();\n\n                    hyper::server::conn::http2::Builder::new(TokioExecutor::new())\n                        .serve_connection(upgraded_io, TowerToHyperService::new(svc))\n                        .await\n                        .unwrap();\n                });\n\n                let mut res = hyper::Response::new(Body::default());\n                *res.status_mut() = http::StatusCode::SWITCHING_PROTOCOLS;\n                res.headers_mut().insert(\n                    hyper::header::UPGRADE,\n                    http::header::HeaderValue::from_static(\"h2c\"),\n                );\n\n                Ok(res)\n            })\n        }\n    }\n}\n"
  },
  {
    "path": "examples/src/health/README.md",
    "content": "# Health checks\n\ngRPC has a [health checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) that defines how health checks for services should be carried out. Tonic supports this protocol with the optional [tonic health crate](https://docs.rs/tonic-health).\n\nThis example uses the crate to set up a HealthServer that will run alongside the application service. In order to test it, you may use community tools like [grpc_health_probe](https://github.com/grpc-ecosystem/grpc-health-probe).\n\nFor example, running the following bash script:\n\n```bash\nwhile [ true ]; do\n./grpc_health_probe -addr=[::1]:50051 -service=helloworld.Greeter\nsleep 1\ndone\n```\n\nwill show the change in health status of the service over time.\n"
  },
  {
    "path": "examples/src/health/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\nuse std::time::Duration;\nuse tonic_health::server::HealthReporter;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n/// This function (somewhat improbably) flips the status of a service every second, in order\n/// that the effect of `tonic_health::HealthReporter::watch` can be easily observed.\nasync fn twiddle_service_status(reporter: HealthReporter) {\n    let mut iter = 0u64;\n    loop {\n        iter += 1;\n        tokio::time::sleep(Duration::from_secs(1)).await;\n\n        if iter % 2 == 0 {\n            reporter.set_serving::<GreeterServer<MyGreeter>>().await;\n        } else {\n            reporter.set_not_serving::<GreeterServer<MyGreeter>>().await;\n        };\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let (health_reporter, health_service) = tonic_health::server::health_reporter();\n    health_reporter\n        .set_serving::<GreeterServer<MyGreeter>>()\n        .await;\n\n    tokio::spawn(twiddle_service_status(health_reporter.clone()));\n\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"HealthServer + GreeterServer listening on {addr}\");\n\n    Server::builder()\n        .add_service(health_service)\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/helloworld/client.rs",
    "content": "use hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/helloworld/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/interceptor/client.rs",
    "content": "use hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\nuse tonic::{\n    Request, Status,\n    codegen::InterceptedService,\n    service::Interceptor,\n    transport::{Channel, Endpoint},\n};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let channel = Endpoint::from_static(\"http://[::1]:50051\")\n        .connect()\n        .await?;\n\n    let mut client = GreeterClient::with_interceptor(channel, intercept);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n\n/// This function will get called on each outbound request. Returning a\n/// `Status` here will cancel the request and have that status returned to\n/// the caller.\nfn intercept(req: Request<()>) -> Result<Request<()>, Status> {\n    println!(\"Intercepting request: {req:?}\");\n    Ok(req)\n}\n\n// You can also use the `Interceptor` trait to create an interceptor type\n// that is easy to name\nstruct MyInterceptor;\n\nimpl Interceptor for MyInterceptor {\n    fn call(&mut self, request: tonic::Request<()>) -> Result<tonic::Request<()>, Status> {\n        Ok(request)\n    }\n}\n\n#[allow(dead_code, unused_variables)]\nasync fn using_named_interceptor() -> Result<(), Box<dyn std::error::Error>> {\n    let channel = Endpoint::from_static(\"http://[::1]:50051\")\n        .connect()\n        .await?;\n\n    let client: GreeterClient<InterceptedService<Channel, MyInterceptor>> =\n        GreeterClient::with_interceptor(channel, MyInterceptor);\n\n    Ok(())\n}\n\n// Using a function pointer type might also be possible if your interceptor is a\n// bare function that doesn't capture any variables\n#[allow(dead_code, unused_variables, clippy::type_complexity)]\nasync fn using_function_pointer_interceptro() -> Result<(), Box<dyn std::error::Error>> {\n    let channel = Endpoint::from_static(\"http://[::1]:50051\")\n        .connect()\n        .await?;\n\n    let client: GreeterClient<\n        InterceptedService<Channel, fn(tonic::Request<()>) -> Result<tonic::Request<()>, Status>>,\n    > = GreeterClient::with_interceptor(channel, intercept);\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/interceptor/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        let extension = request.extensions().get::<MyExtension>().unwrap();\n        println!(\"extension data = {}\", extension.some_piece_of_data);\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    // See examples/src/interceptor/client.rs for an example of how to create a\n    // named interceptor that can be returned from functions or stored in\n    // structs.\n    let svc = GreeterServer::with_interceptor(greeter, intercept);\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder().add_service(svc).serve(addr).await?;\n\n    Ok(())\n}\n\n/// This function will get called on each inbound request, if a `Status`\n/// is returned, it will cancel the request and return that status to the\n/// client.\nfn intercept(mut req: Request<()>) -> Result<Request<()>, Status> {\n    println!(\"Intercepting request: {req:?}\");\n\n    // Set an extension that can be retrieved by `say_hello`\n    req.extensions_mut().insert(MyExtension {\n        some_piece_of_data: \"foo\".to_string(),\n    });\n\n    Ok(req)\n}\n\n#[derive(Clone)]\nstruct MyExtension {\n    some_piece_of_data: String,\n}\n"
  },
  {
    "path": "examples/src/json-codec/client.rs",
    "content": "//! A HelloWorld example that uses JSON instead of protobuf as the message serialization format.\n//!\n//! Generated code is the output of codegen as defined in the `build_json_codec_service` function\n//! in the `examples/build.rs` file. As defined there, the generated code assumes that a module\n//! `crate::common` exists which defines `HelloRequest`, `HelloResponse`, and `JsonCodec`.\n\npub mod common;\nuse common::HelloRequest;\n\npub mod hello_world {\n    include!(concat!(env!(\"OUT_DIR\"), \"/json.helloworld.Greeter.rs\"));\n}\nuse hello_world::greeter_client::GreeterClient;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/json-codec/common.rs",
    "content": "//! This module defines common request/response types as well as the JsonCodec that is used by the\n//! json.helloworld.Greeter service which is defined manually (instead of via proto files) by the\n//! `build_json_codec_service` function in the `examples/build.rs` file.\n\nuse bytes::{Buf, BufMut};\nuse serde::{Deserialize, Serialize};\nuse std::marker::PhantomData;\nuse tonic::{\n    Status,\n    codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder},\n};\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct HelloRequest {\n    pub name: String,\n}\n\n#[derive(Debug, Deserialize, Serialize)]\npub struct HelloResponse {\n    pub message: String,\n}\n\n#[derive(Debug)]\npub struct JsonEncoder<T>(PhantomData<T>);\n\nimpl<T: serde::Serialize> Encoder for JsonEncoder<T> {\n    type Item = T;\n    type Error = Status;\n\n    fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> {\n        serde_json::to_writer(buf.writer(), &item).map_err(|e| Status::internal(e.to_string()))\n    }\n}\n\n#[derive(Debug)]\npub struct JsonDecoder<U>(PhantomData<U>);\n\nimpl<U: serde::de::DeserializeOwned> Decoder for JsonDecoder<U> {\n    type Item = U;\n    type Error = Status;\n\n    fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result<Option<Self::Item>, Self::Error> {\n        if !buf.has_remaining() {\n            return Ok(None);\n        }\n\n        let item: Self::Item =\n            serde_json::from_reader(buf.reader()).map_err(|e| Status::internal(e.to_string()))?;\n        Ok(Some(item))\n    }\n}\n\n/// A [`Codec`] that implements `application/grpc+json` via the serde library.\n#[derive(Debug, Clone)]\npub struct JsonCodec<T, U>(PhantomData<(T, U)>);\n\nimpl<T, U> Default for JsonCodec<T, U> {\n    fn default() -> Self {\n        Self(PhantomData)\n    }\n}\n\nimpl<T, U> Codec for JsonCodec<T, U>\nwhere\n    T: serde::Serialize + Send + 'static,\n    U: serde::de::DeserializeOwned + Send + 'static,\n{\n    type Encode = T;\n    type Decode = U;\n    type Encoder = JsonEncoder<T>;\n    type Decoder = JsonDecoder<U>;\n\n    fn encoder(&mut self) -> Self::Encoder {\n        JsonEncoder(PhantomData)\n    }\n\n    fn decoder(&mut self) -> Self::Decoder {\n        JsonDecoder(PhantomData)\n    }\n}\n"
  },
  {
    "path": "examples/src/json-codec/server.rs",
    "content": "//! A HelloWorld example that uses JSON instead of protobuf as the message serialization format.\n//!\n//! Generated code is the output of codegen as defined in the `build_json_codec_service` function\n//! in the `examples/build.rs` file. As defined there, the generated code assumes that a module\n//! `crate::common` exists which defines `HelloRequest`, `HelloResponse`, and `JsonCodec`.\n\nuse tonic::{Request, Response, Status, transport::Server};\n\npub mod common;\nuse common::{HelloRequest, HelloResponse};\n\npub mod hello_world {\n    include!(concat!(env!(\"OUT_DIR\"), \"/json.helloworld.Greeter.rs\"));\n}\nuse hello_world::greeter_server::{Greeter, GreeterServer};\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloResponse>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = HelloResponse {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/load_balance/client.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, echo_client::EchoClient};\nuse tonic::transport::Channel;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let endpoints = [\"http://[::1]:50051\", \"http://[::1]:50052\"]\n        .iter()\n        .map(|a| Channel::from_static(a));\n\n    let channel = Channel::balance_list(endpoints);\n\n    let mut client = EchoClient::new(channel);\n\n    for _ in 0..12usize {\n        let request = tonic::Request::new(EchoRequest {\n            message: \"hello\".into(),\n        });\n\n        let response = client.unary_echo(request).await?;\n\n        println!(\"RESPONSE={response:?}\");\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/load_balance/server.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse std::net::SocketAddr;\nuse tokio::sync::mpsc;\nuse tonic::{Request, Response, Status, transport::Server};\n\nuse pb::{EchoRequest, EchoResponse};\n\ntype EchoResult<T> = Result<Response<T>, Status>;\n\n#[derive(Debug)]\npub struct EchoServer {\n    addr: SocketAddr,\n}\n\n#[tonic::async_trait]\nimpl pb::echo_server::Echo for EchoServer {\n    async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        let message = format!(\"{} (from {})\", request.into_inner().message, self.addr);\n\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addrs = [\"[::1]:50051\", \"[::1]:50052\"];\n\n    let (tx, mut rx) = mpsc::unbounded_channel();\n\n    for addr in &addrs {\n        let addr = addr.parse()?;\n        let tx = tx.clone();\n\n        let server = EchoServer { addr };\n        let serve = Server::builder()\n            .add_service(pb::echo_server::EchoServer::new(server))\n            .serve(addr);\n\n        tokio::spawn(async move {\n            if let Err(e) = serve.await {\n                eprintln!(\"Error = {e:?}\");\n            }\n\n            tx.send(()).unwrap();\n        });\n    }\n\n    rx.recv().await;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/mock/mock.rs",
    "content": "use hyper_util::rt::TokioIo;\nuse tonic::{\n    Request, Response, Status,\n    transport::{Endpoint, Server, Uri},\n};\nuse tower::service_fn;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\nuse hello_world::{\n    HelloReply, HelloRequest,\n    greeter_client::GreeterClient,\n    greeter_server::{Greeter, GreeterServer},\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let (client, server) = tokio::io::duplex(1024);\n\n    let greeter = MyGreeter::default();\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(GreeterServer::new(greeter))\n            .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n            .await\n    });\n\n    // Move client to an option so we can _move_ the inner value\n    // on the first attempt to connect. All other attempts will fail.\n    let mut client = Some(client);\n    let channel = Endpoint::try_from(\"http://[::]:50051\")?\n        .connect_with_connector(service_fn(move |_: Uri| {\n            let client = client.take();\n\n            async move {\n                if let Some(client) = client {\n                    Ok(TokioIo::new(client))\n                } else {\n                    Err(std::io::Error::other(\"Client already taken\"))\n                }\n            }\n        }))\n        .await?;\n\n    let mut client = GreeterClient::new(channel);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request: {:?}\", request);\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n"
  },
  {
    "path": "examples/src/multiplex/client.rs",
    "content": "pub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\npub mod echo {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse echo::{EchoRequest, echo_client::EchoClient};\nuse hello_world::{HelloRequest, greeter_client::GreeterClient};\nuse tonic::transport::Endpoint;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let channel = Endpoint::from_static(\"http://[::1]:50051\")\n        .connect()\n        .await?;\n\n    let mut greeter_client = GreeterClient::new(channel.clone());\n    let mut echo_client = EchoClient::new(channel);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = greeter_client.say_hello(request).await?;\n\n    println!(\"GREETER RESPONSE={response:?}\");\n\n    let request = tonic::Request::new(EchoRequest {\n        message: \"hello\".into(),\n    });\n\n    let response = echo_client.unary_echo(request).await?;\n\n    println!(\"ECHO RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/multiplex/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\npub mod echo {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse hello_world::{\n    HelloReply, HelloRequest,\n    greeter_server::{Greeter, GreeterServer},\n};\n\nuse echo::{\n    EchoRequest, EchoResponse,\n    echo_server::{Echo, EchoServer},\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n\n    let greeter = GreeterServer::new(MyGreeter::default());\n    let echo = EchoServer::new(MyEcho::default());\n\n    Server::builder()\n        .add_service(greeter)\n        .add_service(echo)\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[derive(Default)]\npub struct MyEcho {}\n\n#[tonic::async_trait]\nimpl Echo for MyEcho {\n    async fn unary_echo(\n        &self,\n        request: Request<EchoRequest>,\n    ) -> Result<Response<EchoResponse>, Status> {\n        let message = request.into_inner().message;\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n"
  },
  {
    "path": "examples/src/reflection/server.rs",
    "content": "use tonic::transport::Server;\nuse tonic::{Request, Response, Status};\n\nmod proto {\n    tonic::include_proto!(\"helloworld\");\n\n    pub(crate) const FILE_DESCRIPTOR_SET: &[u8] =\n        tonic::include_file_descriptor_set!(\"helloworld_descriptor\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl proto::greeter_server::Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<proto::HelloRequest>,\n    ) -> Result<Response<proto::HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = proto::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let service = tonic_reflection::server::Builder::configure()\n        .register_encoded_file_descriptor_set(proto::FILE_DESCRIPTOR_SET)\n        .build_v1()\n        .unwrap();\n\n    let addr = \"[::1]:50052\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    Server::builder()\n        .add_service(service)\n        .add_service(proto::greeter_server::GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/richer-error/client.rs",
    "content": "use tonic_types::StatusExt;\n\nuse hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        // Valid request\n        // name: \"Tonic\".into(),\n        // Name cannot be empty\n        name: \"\".into(),\n        // Name is too long\n        // name: \"some excessively long name\".into(),\n    });\n\n    let response = match client.say_hello(request).await {\n        Ok(response) => response,\n        Err(status) => {\n            println!(\" Error status received. Extracting error details...\\n\");\n\n            let err_details = status.get_error_details();\n\n            if let Some(bad_request) = err_details.bad_request() {\n                // Handle bad_request details\n                println!(\" {bad_request:?}\");\n            }\n            if let Some(help) = err_details.help() {\n                // Handle help details\n                println!(\" {help:?}\");\n            }\n            if let Some(localized_message) = err_details.localized_message() {\n                // Handle localized_message details\n                println!(\" {localized_message:?}\");\n            }\n\n            println!();\n\n            return Ok(());\n        }\n    };\n\n    println!(\" Successful response received.\\n\\n {response:?}\\n\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/richer-error/client_vec.rs",
    "content": "use tonic_types::{ErrorDetail, StatusExt};\n\nuse hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        // Valid request\n        // name: \"Tonic\".into(),\n        // Name cannot be empty\n        name: \"\".into(),\n        // Name is too long\n        // name: \"some excessively long name\".into(),\n    });\n\n    let response = match client.say_hello(request).await {\n        Ok(response) => response,\n        Err(status) => {\n            println!(\" Error status received. Extracting error details...\\n\");\n\n            let err_details = status.get_error_details_vec();\n\n            for (i, err_detail) in err_details.iter().enumerate() {\n                println!(\"err_detail[{i}]\");\n                match err_detail {\n                    ErrorDetail::BadRequest(bad_request) => {\n                        // Handle bad_request details\n                        println!(\" {bad_request:?}\");\n                    }\n                    ErrorDetail::Help(help) => {\n                        // Handle help details\n                        println!(\" {help:?}\");\n                    }\n                    ErrorDetail::LocalizedMessage(localized_message) => {\n                        // Handle localized_message details\n                        println!(\" {localized_message:?}\");\n                    }\n                    _ => {}\n                }\n            }\n\n            println!();\n\n            return Ok(());\n        }\n    };\n\n    println!(\" Successful response received.\\n\\n {response:?}\\n\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/richer-error/server.rs",
    "content": "use tonic::{Code, Request, Response, Status, transport::Server};\nuse tonic_types::{ErrorDetails, StatusExt};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        // Extract request data\n        let name = request.into_inner().name;\n\n        // Create empty ErrorDetails struct\n        let mut err_details = ErrorDetails::new();\n\n        // Add error details conditionally\n        if name.is_empty() {\n            err_details.add_bad_request_violation(\"name\", \"name cannot be empty\");\n        } else if name.len() > 20 {\n            err_details.add_bad_request_violation(\"name\", \"name is too long\");\n        }\n\n        if err_details.has_bad_request_violations() {\n            // Add additional error details if necessary\n            err_details\n                .add_help_link(\"description of link\", \"https://resource.example.local\")\n                .set_localized_message(\"en-US\", \"message for the user\");\n\n            // Generate error status\n            let status = Status::with_error_details(\n                Code::InvalidArgument,\n                \"request contains invalid arguments\",\n                err_details,\n            );\n\n            return Err(status);\n        }\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {name}!\"),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/richer-error/server_vec.rs",
    "content": "use tonic::{Code, Request, Response, Status, transport::Server};\nuse tonic_types::{BadRequest, Help, LocalizedMessage, StatusExt};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        // Extract request data\n        let name = request.into_inner().name;\n\n        // Create empty BadRequest struct\n        let mut bad_request = BadRequest::new(vec![]);\n\n        // Add violations conditionally\n        if name.is_empty() {\n            bad_request.add_violation(\"name\", \"name cannot be empty\");\n        } else if name.len() > 20 {\n            bad_request.add_violation(\"name\", \"name is too long\");\n        }\n\n        if !bad_request.is_empty() {\n            // Add additional error details if necessary\n            let help = Help::with_link(\"description of link\", \"https://resource.example.local\");\n\n            let localized_message = LocalizedMessage::new(\"en-US\", \"message for the user\");\n\n            // Generate error status\n            let status = Status::with_error_details_vec(\n                Code::InvalidArgument,\n                \"request contains invalid arguments\",\n                vec![bad_request.into(), help.into(), localized_message.into()],\n            );\n\n            return Err(status);\n        }\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {name}!\"),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/routeguide/client.rs",
    "content": "use std::error::Error;\nuse std::time::Duration;\n\nuse rand::Rng;\nuse rand::rngs::ThreadRng;\nuse tokio::time;\nuse tonic::Request;\nuse tonic::transport::Channel;\n\nuse routeguide::route_guide_client::RouteGuideClient;\nuse routeguide::{Point, Rectangle, RouteNote};\n\npub mod routeguide {\n    tonic::include_proto!(\"routeguide\");\n}\n\nasync fn print_features(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {\n    let rectangle = Rectangle {\n        lo: Some(Point {\n            latitude: 400_000_000,\n            longitude: -750_000_000,\n        }),\n        hi: Some(Point {\n            latitude: 420_000_000,\n            longitude: -730_000_000,\n        }),\n    };\n\n    let mut stream = client\n        .list_features(Request::new(rectangle))\n        .await?\n        .into_inner();\n\n    while let Some(feature) = stream.message().await? {\n        println!(\"FEATURE = {feature:?}\");\n    }\n\n    Ok(())\n}\n\nasync fn run_record_route(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {\n    let mut rng = rand::rng();\n    let point_count: i32 = rng.random_range(2..100);\n\n    let mut points = vec![];\n    for _ in 0..=point_count {\n        points.push(random_point(&mut rng))\n    }\n\n    println!(\"Traversing {} points\", points.len());\n    let request = Request::new(tokio_stream::iter(points));\n\n    match client.record_route(request).await {\n        Ok(response) => println!(\"SUMMARY: {:?}\", response.into_inner()),\n        Err(e) => println!(\"something went wrong: {e:?}\"),\n    }\n\n    Ok(())\n}\n\nasync fn run_route_chat(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {\n    let start = time::Instant::now();\n\n    let outbound = async_stream::stream! {\n        let mut interval = time::interval(Duration::from_secs(1));\n\n        loop {\n            let time = interval.tick().await;\n            let elapsed = time.duration_since(start);\n            let note = RouteNote {\n                location: Some(Point {\n                    latitude: 409146138 + elapsed.as_secs() as i32,\n                    longitude: -746188906,\n                }),\n                message: format!(\"at {elapsed:?}\"),\n            };\n\n            yield note;\n        }\n    };\n\n    let response = client.route_chat(Request::new(outbound)).await?;\n    let mut inbound = response.into_inner();\n\n    while let Some(note) = inbound.message().await? {\n        println!(\"NOTE = {note:?}\");\n    }\n\n    Ok(())\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = RouteGuideClient::connect(\"http://[::1]:10000\").await?;\n\n    println!(\"*** SIMPLE RPC ***\");\n    let response = client\n        .get_feature(Request::new(Point {\n            latitude: 409_146_138,\n            longitude: -746_188_906,\n        }))\n        .await?;\n    println!(\"RESPONSE = {response:?}\");\n\n    println!(\"\\n*** SERVER STREAMING ***\");\n    print_features(&mut client).await?;\n\n    println!(\"\\n*** CLIENT STREAMING ***\");\n    run_record_route(&mut client).await?;\n\n    println!(\"\\n*** BIDIRECTIONAL STREAMING ***\");\n    run_route_chat(&mut client).await?;\n\n    Ok(())\n}\n\nfn random_point(rng: &mut ThreadRng) -> Point {\n    let latitude = (rng.random_range(0..180) - 90) * 10_000_000;\n    let longitude = (rng.random_range(0..360) - 180) * 10_000_000;\n    Point {\n        latitude,\n        longitude,\n    }\n}\n"
  },
  {
    "path": "examples/src/routeguide/data.rs",
    "content": "use serde::Deserialize;\nuse std::fs::File;\n\n#[derive(Debug, Deserialize)]\nstruct Feature {\n    location: Location,\n    name: String,\n}\n\n#[derive(Debug, Deserialize)]\nstruct Location {\n    latitude: i32,\n    longitude: i32,\n}\n\n#[allow(dead_code)]\npub fn load() -> Vec<crate::routeguide::Feature> {\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let file = File::open(data_dir.join(\"route_guide_db.json\")).expect(\"failed to open data file\");\n\n    let decoded: Vec<Feature> =\n        serde_json::from_reader(&file).expect(\"failed to deserialize features\");\n\n    decoded\n        .into_iter()\n        .map(|feature| crate::routeguide::Feature {\n            name: feature.name,\n            location: Some(crate::routeguide::Point {\n                longitude: feature.location.longitude,\n                latitude: feature.location.latitude,\n            }),\n        })\n        .collect()\n}\n"
  },
  {
    "path": "examples/src/routeguide/server.rs",
    "content": "use std::collections::HashMap;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::time::Instant;\n\nuse tokio::sync::mpsc;\nuse tokio_stream::{Stream, StreamExt, wrappers::ReceiverStream};\nuse tonic::transport::Server;\nuse tonic::{Request, Response, Status};\n\nuse routeguide::route_guide_server::{RouteGuide, RouteGuideServer};\nuse routeguide::{Feature, Point, Rectangle, RouteNote, RouteSummary};\n\npub mod routeguide {\n    tonic::include_proto!(\"routeguide\");\n}\n\nmod data;\n\n#[derive(Debug)]\npub struct RouteGuideService {\n    features: Arc<Vec<Feature>>,\n}\n\n#[tonic::async_trait]\nimpl RouteGuide for RouteGuideService {\n    async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> {\n        println!(\"GetFeature = {:?}\", request);\n\n        for feature in &self.features[..] {\n            if feature.location.as_ref() == Some(request.get_ref()) {\n                return Ok(Response::new(feature.clone()));\n            }\n        }\n\n        Ok(Response::new(Feature::default()))\n    }\n\n    type ListFeaturesStream = ReceiverStream<Result<Feature, Status>>;\n\n    async fn list_features(\n        &self,\n        request: Request<Rectangle>,\n    ) -> Result<Response<Self::ListFeaturesStream>, Status> {\n        println!(\"ListFeatures = {:?}\", request);\n\n        let (tx, rx) = mpsc::channel(4);\n        let features = self.features.clone();\n\n        tokio::spawn(async move {\n            for feature in &features[..] {\n                if in_range(feature.location.as_ref().unwrap(), request.get_ref()) {\n                    println!(\"  => send {feature:?}\");\n                    tx.send(Ok(feature.clone())).await.unwrap();\n                }\n            }\n\n            println!(\" /// done sending\");\n        });\n\n        Ok(Response::new(ReceiverStream::new(rx)))\n    }\n\n    async fn record_route(\n        &self,\n        request: Request<tonic::Streaming<Point>>,\n    ) -> Result<Response<RouteSummary>, Status> {\n        println!(\"RecordRoute\");\n\n        let mut stream = request.into_inner();\n\n        let mut summary = RouteSummary::default();\n        let mut last_point = None;\n        let now = Instant::now();\n\n        while let Some(point) = stream.next().await {\n            let point = point?;\n\n            println!(\"  ==> Point = {point:?}\");\n\n            // Increment the point count\n            summary.point_count += 1;\n\n            // Find features\n            for feature in &self.features[..] {\n                if feature.location.as_ref() == Some(&point) {\n                    summary.feature_count += 1;\n                }\n            }\n\n            // Calculate the distance\n            if let Some(ref last_point) = last_point {\n                summary.distance += calc_distance(last_point, &point);\n            }\n\n            last_point = Some(point);\n        }\n\n        summary.elapsed_time = now.elapsed().as_secs() as i32;\n\n        Ok(Response::new(summary))\n    }\n\n    type RouteChatStream = Pin<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send + 'static>>;\n\n    async fn route_chat(\n        &self,\n        request: Request<tonic::Streaming<RouteNote>>,\n    ) -> Result<Response<Self::RouteChatStream>, Status> {\n        println!(\"RouteChat\");\n\n        let mut notes = HashMap::new();\n        let mut stream = request.into_inner();\n\n        let output = async_stream::try_stream! {\n            while let Some(note) = stream.next().await {\n                let note = note?;\n\n                let location = note.location.unwrap();\n\n                let location_notes = notes.entry(location).or_insert(vec![]);\n                location_notes.push(note);\n\n                for note in location_notes {\n                    yield note.clone();\n                }\n            }\n        };\n\n        Ok(Response::new(Box::pin(output) as Self::RouteChatStream))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:10000\".parse().unwrap();\n\n    println!(\"RouteGuideServer listening on: {addr}\");\n\n    let route_guide = RouteGuideService {\n        features: Arc::new(data::load()),\n    };\n\n    let svc = RouteGuideServer::new(route_guide);\n\n    Server::builder().add_service(svc).serve(addr).await?;\n\n    Ok(())\n}\n\nfn in_range(point: &Point, rect: &Rectangle) -> bool {\n    use std::cmp;\n\n    let lo = rect.lo.as_ref().unwrap();\n    let hi = rect.hi.as_ref().unwrap();\n\n    let left = cmp::min(lo.longitude, hi.longitude);\n    let right = cmp::max(lo.longitude, hi.longitude);\n    let top = cmp::max(lo.latitude, hi.latitude);\n    let bottom = cmp::min(lo.latitude, hi.latitude);\n\n    point.longitude >= left\n        && point.longitude <= right\n        && point.latitude >= bottom\n        && point.latitude <= top\n}\n\n/// Calculates the distance between two points using the \"haversine\" formula.\n/// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.\nfn calc_distance(p1: &Point, p2: &Point) -> i32 {\n    const CORD_FACTOR: f64 = 1e7;\n    const R: f64 = 6_371_000.0; // meters\n\n    let lat1 = p1.latitude as f64 / CORD_FACTOR;\n    let lat2 = p2.latitude as f64 / CORD_FACTOR;\n    let lng1 = p1.longitude as f64 / CORD_FACTOR;\n    let lng2 = p2.longitude as f64 / CORD_FACTOR;\n\n    let lat_rad1 = lat1.to_radians();\n    let lat_rad2 = lat2.to_radians();\n\n    let delta_lat = (lat2 - lat1).to_radians();\n    let delta_lng = (lng2 - lng1).to_radians();\n\n    let a = (delta_lat / 2f64).sin() * (delta_lat / 2f64).sin()\n        + (lat_rad1).cos() * (lat_rad2).cos() * (delta_lng / 2f64).sin() * (delta_lng / 2f64).sin();\n\n    let c = 2f64 * a.sqrt().atan2((1f64 - a).sqrt());\n\n    (R * c) as i32\n}\n"
  },
  {
    "path": "examples/src/streaming/client.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.echo\");\n}\n\nuse std::time::Duration;\nuse tokio_stream::{Stream, StreamExt};\nuse tonic::transport::Channel;\n\nuse pb::{EchoRequest, echo_client::EchoClient};\n\nfn echo_requests_iter() -> impl Stream<Item = EchoRequest> {\n    tokio_stream::iter(1..usize::MAX).map(|i| EchoRequest {\n        message: format!(\"msg {i:02}\"),\n    })\n}\n\nasync fn streaming_echo(client: &mut EchoClient<Channel>, num: usize) {\n    let stream = client\n        .server_streaming_echo(EchoRequest {\n            message: \"foo\".into(),\n        })\n        .await\n        .unwrap()\n        .into_inner();\n\n    // stream is infinite - take just 5 elements and then disconnect\n    let mut stream = stream.take(num);\n    while let Some(item) = stream.next().await {\n        println!(\"\\treceived: {}\", item.unwrap().message);\n    }\n    // stream is dropped here and the disconnect info is sent to server\n}\n\nasync fn bidirectional_streaming_echo(client: &mut EchoClient<Channel>, num: usize) {\n    let in_stream = echo_requests_iter().take(num);\n\n    let response = client\n        .bidirectional_streaming_echo(in_stream)\n        .await\n        .unwrap();\n\n    let mut resp_stream = response.into_inner();\n\n    while let Some(received) = resp_stream.next().await {\n        let received = received.unwrap();\n        println!(\"\\treceived message: `{}`\", received.message);\n    }\n}\n\nasync fn bidirectional_streaming_echo_throttle(client: &mut EchoClient<Channel>, dur: Duration) {\n    let in_stream = echo_requests_iter().throttle(dur);\n\n    let response = client\n        .bidirectional_streaming_echo(in_stream)\n        .await\n        .unwrap();\n\n    let mut resp_stream = response.into_inner();\n\n    while let Some(received) = resp_stream.next().await {\n        let received = received.unwrap();\n        println!(\"\\treceived message: `{}`\", received.message);\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = EchoClient::connect(\"http://[::1]:50051\").await.unwrap();\n\n    println!(\"Streaming echo:\");\n    streaming_echo(&mut client, 5).await;\n    tokio::time::sleep(Duration::from_secs(1)).await; //do not mess server println functions\n\n    // Echo stream that sends 17 requests then graceful end that connection\n    println!(\"\\r\\nBidirectional stream echo:\");\n    bidirectional_streaming_echo(&mut client, 17).await;\n\n    // Echo stream that sends up to `usize::MAX` requests. One request each 2s.\n    // Exiting client with CTRL+C demonstrate how to distinguish broken pipe from\n    // graceful client disconnection (above example) on the server side.\n    println!(\"\\r\\nBidirectional stream echo (kill client with CTLR+C):\");\n    bidirectional_streaming_echo_throttle(&mut client, Duration::from_secs(2)).await;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/streaming/server.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.echo\");\n}\n\nuse std::{error::Error, io::ErrorKind, net::ToSocketAddrs, pin::Pin, time::Duration};\nuse tokio::sync::mpsc;\nuse tokio_stream::{Stream, StreamExt, wrappers::ReceiverStream};\nuse tonic::{Request, Response, Status, Streaming, transport::Server};\n\nuse pb::{EchoRequest, EchoResponse};\n\ntype EchoResult<T> = Result<Response<T>, Status>;\ntype ResponseStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;\n\nfn match_for_io_error(err_status: &Status) -> Option<&std::io::Error> {\n    let mut err: &(dyn Error + 'static) = err_status;\n\n    loop {\n        if let Some(io_err) = err.downcast_ref::<std::io::Error>() {\n            return Some(io_err);\n        }\n\n        // h2::Error do not expose std::io::Error with `source()`\n        // https://github.com/hyperium/h2/pull/462\n        if let Some(h2_err) = err.downcast_ref::<h2::Error>()\n            && let Some(io_err) = h2_err.get_io()\n        {\n            return Some(io_err);\n        }\n\n        err = err.source()?;\n    }\n}\n\n#[derive(Debug)]\npub struct EchoServer {}\n\n#[tonic::async_trait]\nimpl pb::echo_server::Echo for EchoServer {\n    async fn unary_echo(&self, _: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        Err(Status::unimplemented(\"not implemented\"))\n    }\n\n    type ServerStreamingEchoStream = ResponseStream;\n\n    async fn server_streaming_echo(\n        &self,\n        req: Request<EchoRequest>,\n    ) -> EchoResult<Self::ServerStreamingEchoStream> {\n        println!(\"EchoServer::server_streaming_echo\");\n        println!(\"\\tclient connected from: {:?}\", req.remote_addr());\n\n        // creating infinite stream with requested message\n        let repeat = std::iter::repeat(EchoResponse {\n            message: req.into_inner().message,\n        });\n        let mut stream = Box::pin(tokio_stream::iter(repeat).throttle(Duration::from_millis(200)));\n\n        // spawn and channel are required if you want handle \"disconnect\" functionality\n        // the `out_stream` will not be polled after client disconnect\n        let (tx, rx) = mpsc::channel(128);\n        tokio::spawn(async move {\n            while let Some(item) = stream.next().await {\n                match tx.send(Result::<_, Status>::Ok(item)).await {\n                    Ok(_) => {\n                        // item (server response) was queued to be send to client\n                    }\n                    Err(_item) => {\n                        // output_stream was build from rx and both are dropped\n                        break;\n                    }\n                }\n            }\n            println!(\"\\tclient disconnected\");\n        });\n\n        let output_stream = ReceiverStream::new(rx);\n        Ok(Response::new(\n            Box::pin(output_stream) as Self::ServerStreamingEchoStream\n        ))\n    }\n\n    async fn client_streaming_echo(\n        &self,\n        _: Request<Streaming<EchoRequest>>,\n    ) -> EchoResult<EchoResponse> {\n        Err(Status::unimplemented(\"not implemented\"))\n    }\n\n    type BidirectionalStreamingEchoStream = ResponseStream;\n\n    async fn bidirectional_streaming_echo(\n        &self,\n        req: Request<Streaming<EchoRequest>>,\n    ) -> EchoResult<Self::BidirectionalStreamingEchoStream> {\n        println!(\"EchoServer::bidirectional_streaming_echo\");\n\n        let mut in_stream = req.into_inner();\n        let (tx, rx) = mpsc::channel(128);\n\n        // this spawn here is required if you want to handle connection error.\n        // If we just map `in_stream` and write it back as `out_stream` the `out_stream`\n        // will be dropped when connection error occurs and error will never be propagated\n        // to mapped version of `in_stream`.\n        tokio::spawn(async move {\n            while let Some(result) = in_stream.next().await {\n                match result {\n                    Ok(v) => tx\n                        .send(Ok(EchoResponse { message: v.message }))\n                        .await\n                        .expect(\"working rx\"),\n                    Err(err) => {\n                        if let Some(io_err) = match_for_io_error(&err)\n                            && io_err.kind() == ErrorKind::BrokenPipe\n                        {\n                            // here you can handle special case when client\n                            // disconnected in unexpected way\n                            eprintln!(\"\\tclient disconnected: broken pipe\");\n                            break;\n                        }\n\n                        match tx.send(Err(err)).await {\n                            Ok(_) => (),\n                            Err(_err) => break, // response was dropped\n                        }\n                    }\n                }\n            }\n            println!(\"\\tstream ended\");\n        });\n\n        // echo just write the same data that was received\n        let out_stream = ReceiverStream::new(rx);\n\n        Ok(Response::new(\n            Box::pin(out_stream) as Self::BidirectionalStreamingEchoStream\n        ))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let server = EchoServer {};\n    Server::builder()\n        .add_service(pb::echo_server::EchoServer::new(server))\n        .serve(\"[::1]:50051\".to_socket_addrs().unwrap().next().unwrap())\n        .await\n        .unwrap();\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/tls/client.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"/grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, echo_client::EchoClient};\nuse tonic::transport::{Certificate, Channel, ClientTlsConfig};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let pem = std::fs::read_to_string(data_dir.join(\"tls/ca.pem\"))?;\n    let ca = Certificate::from_pem(pem);\n\n    let tls = ClientTlsConfig::new()\n        .ca_certificate(ca)\n        .domain_name(\"example.com\");\n\n    let channel = Channel::from_static(\"https://[::1]:50051\")\n        .tls_config(tls)?\n        .connect()\n        .await?;\n\n    let mut client = EchoClient::new(channel);\n    let request = tonic::Request::new(EchoRequest {\n        message: \"hello\".into(),\n    });\n\n    let response = client.unary_echo(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/tls/server.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"/grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, EchoResponse};\nuse tonic::{\n    Request, Response, Status,\n    transport::{\n        Identity, Server, ServerTlsConfig,\n        server::{TcpConnectInfo, TlsConnectInfo},\n    },\n};\n\ntype EchoResult<T> = Result<Response<T>, Status>;\n\n#[derive(Default)]\npub struct EchoServer {}\n\n#[tonic::async_trait]\nimpl pb::echo_server::Echo for EchoServer {\n    async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        let conn_info = request\n            .extensions()\n            .get::<TlsConnectInfo<TcpConnectInfo>>()\n            .unwrap();\n        println!(\n            \"Got a request from {:?} with info {:?}\",\n            request.remote_addr(),\n            conn_info\n        );\n\n        let message = request.into_inner().message;\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let cert = std::fs::read_to_string(data_dir.join(\"tls/server.pem\"))?;\n    let key = std::fs::read_to_string(data_dir.join(\"tls/server.key\"))?;\n\n    let identity = Identity::from_pem(cert, key);\n\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let server = EchoServer::default();\n\n    Server::builder()\n        .tls_config(ServerTlsConfig::new().identity(identity))?\n        .add_service(pb::echo_server::EchoServer::new(server))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/tls_client_auth/client.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, echo_client::EchoClient};\nuse tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let server_root_ca_cert = std::fs::read_to_string(data_dir.join(\"tls/ca.pem\"))?;\n    let server_root_ca_cert = Certificate::from_pem(server_root_ca_cert);\n    let client_cert = std::fs::read_to_string(data_dir.join(\"tls/client1.pem\"))?;\n    let client_key = std::fs::read_to_string(data_dir.join(\"tls/client1.key\"))?;\n    let client_identity = Identity::from_pem(client_cert, client_key);\n\n    let tls = ClientTlsConfig::new()\n        .domain_name(\"localhost\")\n        .ca_certificate(server_root_ca_cert)\n        .identity(client_identity);\n\n    let channel = Channel::from_static(\"https://[::1]:50051\")\n        .tls_config(tls)?\n        .connect()\n        .await?;\n\n    let mut client = EchoClient::new(channel);\n\n    let request = tonic::Request::new(EchoRequest {\n        message: \"hello\".into(),\n    });\n\n    let response = client.unary_echo(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/tls_client_auth/server.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"grpc.examples.unaryecho\");\n}\n\nuse pb::{EchoRequest, EchoResponse};\nuse tonic::transport::{Certificate, Identity, Server, ServerTlsConfig};\nuse tonic::{Request, Response, Status};\n\ntype EchoResult<T> = Result<Response<T>, Status>;\n\n#[derive(Default)]\npub struct EchoServer {}\n\n#[tonic::async_trait]\nimpl pb::echo_server::Echo for EchoServer {\n    async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        let certs = request\n            .peer_certs()\n            .expect(\"Client did not send its certs!\");\n\n        println!(\"Got {} peer certs!\", certs.len());\n\n        let message = request.into_inner().message;\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let cert = std::fs::read_to_string(data_dir.join(\"tls/server.pem\"))?;\n    let key = std::fs::read_to_string(data_dir.join(\"tls/server.key\"))?;\n    let server_identity = Identity::from_pem(cert, key);\n\n    let client_ca_cert = std::fs::read_to_string(data_dir.join(\"tls/client_ca.pem\"))?;\n    let client_ca_cert = Certificate::from_pem(client_ca_cert);\n\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let server = EchoServer::default();\n\n    let tls = ServerTlsConfig::new()\n        .identity(server_identity)\n        .client_ca_root(client_ca_cert);\n\n    Server::builder()\n        .tls_config(tls)?\n        .add_service(pb::echo_server::EchoServer::new(server))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/tls_rustls/client.rs",
    "content": "//! This examples shows how you can combine `hyper-rustls` and `tonic` to\n//! provide a custom `ClientConfig` for the tls configuration.\n\npub mod pb {\n    tonic::include_proto!(\"/grpc.examples.unaryecho\");\n}\n\nuse hyper::Uri;\nuse hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};\nuse pb::{EchoRequest, echo_client::EchoClient};\nuse tokio_rustls::rustls::{\n    pki_types::{CertificateDer, pem::PemObject as _},\n    {ClientConfig, RootCertStore},\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let fd = std::fs::File::open(data_dir.join(\"tls/ca.pem\"))?;\n\n    let mut roots = RootCertStore::empty();\n\n    let mut buf = std::io::BufReader::new(&fd);\n    let certs = CertificateDer::pem_reader_iter(&mut buf).collect::<Result<Vec<_>, _>>()?;\n    roots.add_parsable_certificates(certs.into_iter());\n\n    let tls = ClientConfig::builder()\n        .with_root_certificates(roots)\n        .with_no_client_auth();\n\n    let mut http = HttpConnector::new();\n    http.enforce_http(false);\n\n    // We have to do some wrapping here to map the request type from\n    // `https://example.com` -> `https://[::1]:50051` because `rustls`\n    // doesn't accept ip's as `ServerName`.\n    let connector = tower::ServiceBuilder::new()\n        .layer_fn(move |s| {\n            let tls = tls.clone();\n\n            hyper_rustls::HttpsConnectorBuilder::new()\n                .with_tls_config(tls)\n                .https_or_http()\n                .enable_http2()\n                .wrap_connector(s)\n        })\n        // Since our cert is signed with `example.com` but we actually want to connect\n        // to a local server we will override the Uri passed from the `HttpsConnector`\n        // and map it to the correct `Uri` that will connect us directly to the local server.\n        .map_request(|_| Uri::from_static(\"https://[::1]:50051\"))\n        .service(http);\n\n    let client = hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(connector);\n\n    // Using `with_origin` will let the codegenerated client set the `scheme` and\n    // `authority` from the provided `Uri`.\n    let uri = Uri::from_static(\"https://example.com\");\n    let mut client = EchoClient::with_origin(client, uri);\n\n    let request = tonic::Request::new(EchoRequest {\n        message: \"hello\".into(),\n    });\n\n    let response = client.unary_echo(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/tls_rustls/server.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"/grpc.examples.unaryecho\");\n}\n\nuse hyper::server::conn::http2::Builder;\nuse hyper_util::{\n    rt::{TokioExecutor, TokioIo},\n    service::TowerToHyperService,\n};\nuse pb::{EchoRequest, EchoResponse};\nuse std::sync::Arc;\nuse tokio::net::TcpListener;\nuse tokio_rustls::{\n    TlsAcceptor,\n    rustls::{\n        ServerConfig,\n        pki_types::{CertificateDer, PrivateKeyDer, pem::PemObject as _},\n    },\n};\nuse tonic::{Request, Response, Status, body::Body, service::Routes};\nuse tower::ServiceExt;\nuse tower_http::ServiceBuilderExt;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let data_dir = std::path::PathBuf::from_iter([std::env!(\"CARGO_MANIFEST_DIR\"), \"data\"]);\n    let certs = {\n        let fd = std::fs::File::open(data_dir.join(\"tls/server.pem\"))?;\n        let mut buf = std::io::BufReader::new(&fd);\n        CertificateDer::pem_reader_iter(&mut buf).collect::<Result<Vec<_>, _>>()?\n    };\n    let key = {\n        let fd = std::fs::File::open(data_dir.join(\"tls/server.key\"))?;\n        let mut buf = std::io::BufReader::new(&fd);\n        PrivateKeyDer::from_pem_reader(&mut buf)?\n    };\n\n    let mut tls = ServerConfig::builder()\n        .with_no_client_auth()\n        .with_single_cert(certs, key)?;\n    tls.alpn_protocols = vec![b\"h2\".to_vec()];\n\n    let server = EchoServer::default();\n\n    let svc = Routes::new(pb::echo_server::EchoServer::new(server)).prepare();\n\n    let http = Builder::new(TokioExecutor::new());\n\n    let listener = TcpListener::bind(\"[::1]:50051\").await?;\n    let tls_acceptor = TlsAcceptor::from(Arc::new(tls));\n\n    loop {\n        let (conn, addr) = match listener.accept().await {\n            Ok(incoming) => incoming,\n            Err(e) => {\n                eprintln!(\"Error accepting connection: {e}\");\n                continue;\n            }\n        };\n\n        let http = http.clone();\n        let tls_acceptor = tls_acceptor.clone();\n        let svc = svc.clone();\n\n        tokio::spawn(async move {\n            let mut certificates = Vec::new();\n\n            let conn = tls_acceptor\n                .accept_with(conn, |info| {\n                    if let Some(certs) = info.peer_certificates() {\n                        for cert in certs {\n                            certificates.push(cert.clone());\n                        }\n                    }\n                })\n                .await\n                .unwrap();\n\n            let svc = tower::ServiceBuilder::new()\n                .add_extension(Arc::new(ConnInfo { addr, certificates }))\n                .service(svc);\n\n            http.serve_connection(\n                TokioIo::new(conn),\n                TowerToHyperService::new(\n                    svc.map_request(|req: http::Request<_>| req.map(Body::new)),\n                ),\n            )\n            .await\n            .unwrap();\n        });\n    }\n}\n\n#[derive(Debug)]\nstruct ConnInfo {\n    addr: std::net::SocketAddr,\n    certificates: Vec<CertificateDer<'static>>,\n}\n\ntype EchoResult<T> = Result<Response<T>, Status>;\n\n#[derive(Default)]\npub struct EchoServer {}\n\n#[tonic::async_trait]\nimpl pb::echo_server::Echo for EchoServer {\n    async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> {\n        let conn_info = request.extensions().get::<Arc<ConnInfo>>().unwrap();\n        println!(\n            \"Got a request from: {:?} with certs: {:?}\",\n            conn_info.addr, conn_info.certificates\n        );\n\n        let message = request.into_inner().message;\n        Ok(Response::new(EchoResponse { message }))\n    }\n}\n"
  },
  {
    "path": "examples/src/tower/client.rs",
    "content": "use hello_world::HelloRequest;\nuse hello_world::greeter_client::GreeterClient;\nuse service::AuthSvc;\nuse tower::ServiceBuilder;\n\nuse tonic::{Request, Status, transport::Channel};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let channel = Channel::from_static(\"http://[::1]:50051\").connect().await?;\n\n    let channel = ServiceBuilder::new()\n        // Interceptors can be also be applied as middleware\n        .layer(tonic::service::InterceptorLayer::new(intercept))\n        .layer_fn(AuthSvc::new)\n        .service(channel);\n\n    let mut client = GreeterClient::new(channel);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n\n// An interceptor function.\nfn intercept(req: Request<()>) -> Result<Request<()>, Status> {\n    println!(\"received {req:?}\");\n    Ok(req)\n}\n\nmod service {\n    use http::{Request, Response};\n    use std::future::Future;\n    use std::pin::Pin;\n    use std::task::{Context, Poll};\n    use tonic::body::Body;\n    use tonic::transport::Channel;\n    use tower::Service;\n\n    pub struct AuthSvc {\n        inner: Channel,\n    }\n\n    impl AuthSvc {\n        pub fn new(inner: Channel) -> Self {\n            AuthSvc { inner }\n        }\n    }\n\n    impl Service<Request<Body>> for AuthSvc {\n        type Response = Response<Body>;\n        type Error = Box<dyn std::error::Error + Send + Sync>;\n        #[allow(clippy::type_complexity)]\n        type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;\n\n        fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            self.inner.poll_ready(cx).map_err(Into::into)\n        }\n\n        fn call(&mut self, req: Request<Body>) -> Self::Future {\n            // See: https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services\n            let clone = self.inner.clone();\n            let mut inner = std::mem::replace(&mut self.inner, clone);\n\n            Box::pin(async move {\n                // Do extra async work here...\n                let response = inner.call(req).await?;\n\n                Ok(response)\n            })\n        }\n    }\n}\n"
  },
  {
    "path": "examples/src/tower/server.rs",
    "content": "use std::{\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tonic::{Request, Response, Status, transport::Server};\nuse tower::{Layer, Service};\n\nuse hello_world::greeter_server::{Greeter, GreeterServer};\nuse hello_world::{HelloReply, HelloRequest};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        println!(\"Got a request from {:?}\", request.remote_addr());\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    println!(\"GreeterServer listening on {addr}\");\n\n    let svc = GreeterServer::new(greeter);\n\n    // The stack of middleware that our service will be wrapped in\n    let layer = tower::ServiceBuilder::new()\n        // Apply our own middleware\n        .layer(MyMiddlewareLayer::default())\n        // Interceptors can be also be applied as middleware\n        .layer(tonic::service::InterceptorLayer::new(intercept))\n        .into_inner();\n\n    Server::builder()\n        // Wrap all services in the middleware stack\n        .layer(layer)\n        .add_service(svc)\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n\n// An interceptor function.\nfn intercept(req: Request<()>) -> Result<Request<()>, Status> {\n    Ok(req)\n}\n\n#[derive(Debug, Clone, Default)]\nstruct MyMiddlewareLayer {}\n\nimpl<S> Layer<S> for MyMiddlewareLayer {\n    type Service = MyMiddleware<S>;\n\n    fn layer(&self, service: S) -> Self::Service {\n        MyMiddleware { inner: service }\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct MyMiddleware<S> {\n    inner: S,\n}\n\ntype BoxFuture<'a, T> = Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;\n\nimpl<S, ReqBody, ResBody> Service<http::Request<ReqBody>> for MyMiddleware<S>\nwhere\n    S: Service<http::Request<ReqBody>, Response = http::Response<ResBody>> + Clone + Send + 'static,\n    S::Future: Send + 'static,\n    ReqBody: Send + 'static,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, req: http::Request<ReqBody>) -> Self::Future {\n        // See: https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services\n        let clone = self.inner.clone();\n        let mut inner = std::mem::replace(&mut self.inner, clone);\n\n        Box::pin(async move {\n            // Do extra async work here...\n            let response = inner.call(req).await?;\n\n            Ok(response)\n        })\n    }\n}\n"
  },
  {
    "path": "examples/src/tracing/client.rs",
    "content": "pub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\nuse hello_world::{HelloRequest, greeter_client::GreeterClient};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    tracing_subscriber::FmtSubscriber::builder()\n        .with_max_level(tracing::Level::DEBUG)\n        .init();\n\n    say_hi(\"Bob\".into()).await?;\n\n    Ok(())\n}\n\n#[tracing::instrument]\nasync fn say_hi(name: String) -> Result<(), Box<dyn std::error::Error>> {\n    let mut client = GreeterClient::connect(\"http://[::1]:50051\").await?;\n\n    let request = tonic::Request::new(HelloRequest { name });\n\n    tracing::info!(\n        message = \"Sending request.\",\n        request = %request.get_ref().name\n    );\n\n    let response = client.say_hello(request).await?;\n\n    tracing::info!(\n        message = \"Got a response.\",\n        response = %response.get_ref().message\n    );\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/tracing/server.rs",
    "content": "use tonic::{Request, Response, Status, transport::Server};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\nuse hello_world::{\n    HelloReply, HelloRequest,\n    greeter_server::{Greeter, GreeterServer},\n};\n\n#[derive(Debug, Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    #[tracing::instrument]\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        tracing::info!(\"received request\");\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n\n        tracing::debug!(\"sending response\");\n\n        Ok(Response::new(reply))\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    tracing_subscriber::fmt()\n        .with_max_level(tracing::Level::DEBUG)\n        .init();\n\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = MyGreeter::default();\n\n    tracing::info!(message = \"Starting server.\", %addr);\n\n    Server::builder()\n        .trace_fn(|_| tracing::info_span!(\"helloworld_server\"))\n        .add_service(GreeterServer::new(greeter))\n        .serve(addr)\n        .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/src/uds/client_standard.rs",
    "content": "#![cfg_attr(not(unix), allow(unused_imports))]\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\nuse hello_world::{HelloRequest, greeter_client::GreeterClient};\n\n#[cfg(unix)]\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    // Unix socket URI follows [RFC-3986](https://datatracker.ietf.org/doc/html/rfc3986)\n    // which is aligned with [the gRPC naming convention](https://github.com/grpc/grpc/blob/master/doc/naming.md).\n    // - unix:relative_path\n    // - unix:///absolute_path\n    let path = \"unix:///tmp/tonic/helloworld\";\n\n    let mut client = GreeterClient::connect(path).await?;\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n\n#[cfg(not(unix))]\nfn main() {\n    panic!(\"The `uds` example only works on unix systems!\");\n}\n"
  },
  {
    "path": "examples/src/uds/client_with_connector.rs",
    "content": "#![cfg_attr(not(unix), allow(unused_imports))]\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\nuse hello_world::{HelloRequest, greeter_client::GreeterClient};\nuse hyper_util::rt::TokioIo;\n#[cfg(unix)]\nuse tokio::net::UnixStream;\nuse tonic::transport::{Endpoint, Uri};\nuse tower::service_fn;\n\n#[cfg(unix)]\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    // We will ignore this uri because uds do not use it\n    // if your connector does use the uri it will be provided\n    // as the request to the `MakeConnection`.\n\n    let channel = Endpoint::try_from(\"http://[::]:50051\")?\n        .connect_with_connector(service_fn(|_: Uri| async {\n            let path = \"/tmp/tonic/helloworld\";\n\n            // Connect to a Uds socket\n            Ok::<_, std::io::Error>(TokioIo::new(UnixStream::connect(path).await?))\n        }))\n        .await?;\n\n    let mut client = GreeterClient::new(channel);\n\n    let request = tonic::Request::new(HelloRequest {\n        name: \"Tonic\".into(),\n    });\n\n    let response = client.say_hello(request).await?;\n\n    println!(\"RESPONSE={response:?}\");\n\n    Ok(())\n}\n\n#[cfg(not(unix))]\nfn main() {\n    panic!(\"The `uds` example only works on unix systems!\");\n}\n"
  },
  {
    "path": "examples/src/uds/server.rs",
    "content": "#![cfg_attr(not(unix), allow(unused_imports))]\n\nuse std::path::Path;\n#[cfg(unix)]\nuse tokio::net::UnixListener;\n#[cfg(unix)]\nuse tokio_stream::wrappers::UnixListenerStream;\n#[cfg(unix)]\nuse tonic::transport::server::UdsConnectInfo;\nuse tonic::{Request, Response, Status, transport::Server};\n\npub mod hello_world {\n    tonic::include_proto!(\"helloworld\");\n}\n\nuse hello_world::{\n    HelloReply, HelloRequest,\n    greeter_server::{Greeter, GreeterServer},\n};\n\n#[derive(Default)]\npub struct MyGreeter {}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(\n        &self,\n        request: Request<HelloRequest>,\n    ) -> Result<Response<HelloReply>, Status> {\n        #[cfg(unix)]\n        {\n            let conn_info = request.extensions().get::<UdsConnectInfo>().unwrap();\n            println!(\"Got a request {request:?} with info {conn_info:?}\");\n        }\n\n        let reply = hello_world::HelloReply {\n            message: format!(\"Hello {}!\", request.into_inner().name),\n        };\n        Ok(Response::new(reply))\n    }\n}\n\n#[cfg(unix)]\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let path = \"/tmp/tonic/helloworld\";\n\n    std::fs::create_dir_all(Path::new(path).parent().unwrap())?;\n\n    let greeter = MyGreeter::default();\n\n    let uds = UnixListener::bind(path)?;\n    let uds_stream = UnixListenerStream::new(uds);\n\n    Server::builder()\n        .add_service(GreeterServer::new(greeter))\n        .serve_with_incoming(uds_stream)\n        .await?;\n\n    Ok(())\n}\n\n#[cfg(not(unix))]\nfn main() {\n    panic!(\"The `uds` example only works on unix systems!\");\n}\n"
  },
  {
    "path": "flake.nix",
    "content": "{\n  description = \"Description for the project\";\n\n  inputs = {\n    flake-parts.url = \"github:hercules-ci/flake-parts\";\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n    fenix = {\n      url = \"github:nix-community/fenix\";\n      inputs.nixpkgs.follows = \"nixpkgs\";\n    };\n\n    git-hooks = {\n      url = \"github:cachix/git-hooks.nix\";\n      inputs = {\n        nixpkgs.follows = \"nixpkgs\";\n      };\n    };\n  };\n\n  outputs =\n    inputs@{ self, flake-parts, ... }:\n    flake-parts.lib.mkFlake { inherit inputs; } {\n      imports = [\n        inputs.git-hooks.flakeModule\n      ];\n      systems = [\n        \"x86_64-linux\"\n        \"aarch64-linux\"\n        \"aarch64-darwin\"\n        \"x86_64-darwin\"\n      ];\n      perSystem =\n        {\n          config,\n          pkgs,\n          system,\n          ...\n        }:\n        let\n          rustToolchain = pkgs.fenix.stable;\n        in\n        {\n          _module.args.pkgs = import inputs.nixpkgs {\n            inherit system;\n            overlays = [ inputs.fenix.overlays.default ];\n            config = { };\n          };\n\n          formatter = config.treefmt.build.wrapper;\n          checks.formatting = config.treefmt.build.check self;\n\n          pre-commit = {\n            check.enable = true;\n            settings.hooks = {\n              actionlint.enable = true;\n              shellcheck.enable = true;\n              clippy = {\n                enable = true;\n                packageOverrides = {\n                  cargo = rustToolchain.cargo;\n                  clippy = rustToolchain.clippy;\n                };\n              };\n              cargo-check = {\n                enable = true;\n                package = rustToolchain.cargo;\n                entry = \"${rustToolchain.cargo}/bin/cargo check --workspace --all-features\";\n                files = \"\\\\.rs$\";\n                pass_filenames = false;\n              };\n              rustfmt = {\n                enable = true;\n                packageOverrides = {\n                  rustfmt = rustToolchain.rustfmt;\n                  cargo = rustToolchain.cargo;\n                };\n              };\n            };\n          };\n\n          devShells.default = pkgs.mkShell {\n            packages = with pkgs; [\n              cargo-nextest\n              pre-commit\n              cmake\n\n              (rustToolchain.withComponents [\n                \"cargo\"\n                \"clippy\"\n                \"rust-src\"\n                \"rustc\"\n                \"rustfmt\"\n                \"rust-analyzer\"\n              ])\n            ];\n\n            hardeningDisable = [ \"fortify\" ];\n\n            shellHook = ''\n              ${config.pre-commit.installationScript}\n            '';\n          };\n\n          # App for running the full CI udeps check\n          # `nix run .#udeps-ci`\n          apps.udeps-ci = {\n            type = \"app\";\n            program = \"${pkgs.writeShellScript \"udeps-ci\" ''\n              set -e\n              export PATH=\"${pkgs.rustup}/bin:${pkgs.cargo-udeps}/bin:${pkgs.cargo-hack}/bin:$PATH\"\n\n              # Ensure nightly toolchain is installed\n              if ! rustup toolchain list | grep -q \"nightly-2025-03-27\"; then\n                echo \"Installing nightly-2025-03-27 toolchain...\"\n                rustup toolchain install nightly-2025-03-27\n              fi\n\n              # Set the toolchain for this run\n              export RUSTUP_TOOLCHAIN=nightly-2025-03-27\n\n              echo \"Running cargo hack udeps...\"\n              cargo hack udeps --workspace --exclude-features=_tls-any,tls,tls-aws-lc,tls-ring,tls-connect-info --each-feature\n\n              echo \"Running tonic TLS feature checks...\"\n              cargo udeps --package tonic --features tls-ring,transport\n              cargo udeps --package tonic --features tls-ring,server\n              cargo udeps --package tonic --features tls-ring,channel\n              cargo udeps --package tonic --features tls-aws-lc,transport\n              cargo udeps --package tonic --features tls-aws-lc,server\n              cargo udeps --package tonic --features tls-aws-lc,channel\n              cargo udeps --package tonic --features tls-connect-info\n\n              echo \"✓ All udeps checks passed!\"\n            ''}\";\n          };\n        };\n    };\n}\n"
  },
  {
    "path": "grpc/Cargo.toml",
    "content": "[package]\nname = \"grpc\"\nversion = \"0.9.0-alpha.1\"\nedition = \"2024\"\nauthors = [\"gRPC Authors\"]\nlicense = \"MIT\"\nrust-version = { workspace = true }\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n    \"bytes::*\",\n    \"tonic::*\",\n    \"futures_core::stream::Stream\",\n    \"tokio::sync::oneshot::Sender\",\n]\n\n[features]\ndefault = [\"dns\", \"_runtime-tokio\", \"tls-rustls\"]\ndns = [\"dep:hickory-resolver\", \"_runtime-tokio\"]\n# The following feature is used to ensure all modules use the runtime\n# abstraction instead of using tokio directly.\n# Using tower/buffer enables tokio's rt feature even though it's possible to\n# create Buffers with a user provided executor.\n_runtime-tokio = [\n    \"tokio/rt\",\n    \"tokio/net\",\n    \"tokio/time\",\n    \"dep:socket2\",\n    \"dep:tower\",\n]\n# Used for testing with udeps as it wants this feature to exist\n# to be able to do its checks.\ntower = [\"_runtime-tokio\"]\ntls-rustls = [\n    \"dep:rustls\",\n    \"dep:rustls-pemfile\",\n    \"dep:rustls-pki-types\",\n    \"dep:tokio-rustls\",\n    \"dep:rustls-platform-verifier\",\n    \"dep:rustls-webpki\",\n]\n\n[dependencies]\nbytes = \"1.10.1\"\nhickory-resolver = { version = \"0.25.1\", optional = true }\nhttp = \"1.1.0\"\nhttp-body = \"1.0.1\"\nhyper = { version = \"1.6.0\", features = [\"client\", \"http2\"] }\nparking_lot = \"0.12.4\"\npin-project-lite = \"0.2.16\"\nrand = \"0.9\"\nrustls = { version = \"0.23\", optional = true, default-features = false, features = [\n    \"tls12\",\n    \"logging\",\n    \"std\",\n] }\nrustls-pemfile = { version = \"2.1\", optional = true, default-features = false, features = [\n    \"std\",\n] }\nrustls-pki-types = { version = \"1.8\", optional = true, default-features = false }\nrustls-platform-verifier = { version = \"0.6\", optional = true, default-features = false }\nrustls-webpki = { version = \"0.102\", optional = true, default-features = false }\nserde = { version = \"1.0.219\", features = [\"derive\"] }\nserde_json = \"1.0.140\"\nsocket2 = { version = \"0.6\", optional = true }\ntokio = { version = \"1.37.0\", features = [\"sync\", \"macros\"] }\ntokio-rustls = { version = \"0.26\", optional = true, default-features = false }\ntokio-stream = { version = \"0.1.17\", default-features = false }\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false, features = [\n    \"codegen\",\n] }\ntower = { version = \"0.5.2\", features = [\n    \"limit\",\n    \"util\",\n    \"buffer\",\n], optional = true }\ntower-service = \"0.3.3\"\ntrait-variant = \"0.1.2\"\nurl = \"2.5.0\"\n\n[dev-dependencies]\nasync-stream = \"0.3.6\"\nhickory-server = \"0.25.2\"\nprost = \"0.14.0\"\nrustls = { version = \"0.23\", default-features = false, features = [\"ring\"] }\ntempfile = \"3.26\"\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false, features = [\n    \"server\",\n    \"router\",\n] }\ntonic-prost = { version = \"0.14.0\", path = \"../tonic-prost\" }\n"
  },
  {
    "path": "grpc/examples/inmemory.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse bytes::Buf;\nuse bytes::Bytes;\nuse grpc::client;\nuse grpc::client::CallOptions;\nuse grpc::client::Channel;\nuse grpc::client::ChannelOptions;\nuse grpc::client::Invoke;\nuse grpc::client::RecvStream as _;\nuse grpc::client::SendStream as _;\nuse grpc::core::ClientResponseStreamItem;\nuse grpc::core::RecvMessage;\nuse grpc::core::RequestHeaders;\nuse grpc::core::SendMessage;\nuse grpc::core::ServerResponseStreamItem;\nuse grpc::credentials::InsecureChannelCredentials;\nuse grpc::inmemory;\nuse grpc::server;\nuse grpc::server::Handle;\n\nstruct Handler {\n    id: String,\n}\n\n#[derive(Debug, Default)]\nstruct MyReqMessage(String);\n\nimpl SendMessage for MyReqMessage {\n    fn encode(&self) -> Result<Box<dyn Buf + Send + Sync>, String> {\n        Ok(Box::new(Bytes::from(self.0.clone())))\n    }\n}\nimpl RecvMessage for MyReqMessage {\n    fn decode(&mut self, data: &mut dyn Buf) -> Result<(), String> {\n        let b = data.copy_to_bytes(data.remaining());\n        self.0 = String::from_utf8(b.to_vec()).map_err(|e| e.to_string())?;\n        Ok(())\n    }\n}\n\n#[derive(Debug, Default)]\nstruct MyResMessage(String);\nimpl SendMessage for MyResMessage {\n    fn encode(&self) -> Result<Box<dyn Buf + Send + Sync>, String> {\n        Ok(Box::new(Bytes::from(self.0.clone())))\n    }\n}\nimpl RecvMessage for MyResMessage {\n    fn decode(&mut self, data: &mut dyn Buf) -> Result<(), String> {\n        let b = data.copy_to_bytes(data.remaining());\n        self.0 = String::from_utf8(b.to_vec()).map_err(|e| e.to_string())?;\n        Ok(())\n    }\n}\n\nimpl Handle for Handler {\n    async fn handle(\n        &self,\n        headers: RequestHeaders,\n        tx: &mut impl server::SendStream,\n        mut rx: impl server::RecvStream + 'static,\n    ) {\n        let method = headers.method_name().clone();\n        let id = self.id.clone();\n        // Send headers\n        let _ = tx\n            .send(\n                ServerResponseStreamItem::Headers(grpc::core::ResponseHeaders::default()),\n                server::SendOptions::default(),\n            )\n            .await;\n\n        let mut req_msg = MyReqMessage::default();\n        while rx.next(&mut req_msg).await.is_ok() {\n            let res_msg = MyResMessage(format!(\n                \"Server {}: responding to: {}; msg: {}\",\n                id, method, req_msg.0,\n            ));\n            let _ = tx\n                .send(\n                    ServerResponseStreamItem::Message(&res_msg),\n                    server::SendOptions::default(),\n                )\n                .await;\n        }\n        // Send trailers\n        let _ = tx\n            .send(\n                ServerResponseStreamItem::Trailers(grpc::core::Trailers::new(grpc::Status::new(\n                    grpc::StatusCode::Ok,\n                    \"OK\",\n                ))),\n                server::SendOptions::default(),\n            )\n            .await;\n    }\n}\n\n#[tokio::main]\nasync fn main() {\n    inmemory::reg();\n    let mut listeners = Vec::new();\n    for _ in 0..3 {\n        let lis = inmemory::InMemoryListener::new();\n        let mut srv = grpc::server::Server::new();\n        srv.set_handler(Handler { id: lis.id() });\n        let lis_clone = lis.clone();\n        tokio::task::spawn(async move {\n            srv.serve(&lis_clone).await;\n            println!(\"serve returned for listener {}!\", lis_clone.id());\n        });\n        listeners.push(lis);\n    }\n\n    let ids: Vec<String> = listeners.iter().map(|lis| lis.id()).collect();\n    let target = format!(\"inmemory:///{}\", ids.join(\",\"));\n    println!(\"Creating channel for {target}\");\n    let chan_opts = ChannelOptions::default();\n    let chan = Channel::new(\n        target.as_str(),\n        InsecureChannelCredentials::new(),\n        chan_opts,\n    );\n\n    let expected_servers: std::collections::HashSet<_> = ids.into_iter().collect();\n    let mut responding_servers = std::collections::HashSet::new();\n    let start = std::time::Instant::now();\n    while responding_servers != expected_servers\n        && start.elapsed() < std::time::Duration::from_secs(3)\n    {\n        let server_id = run_rpc(&chan).await;\n        if !server_id.is_empty() {\n            responding_servers.insert(server_id);\n        }\n        tokio::time::sleep(std::time::Duration::from_millis(10)).await;\n    }\n\n    println!(\"Responding servers: {:?}\", responding_servers);\n    assert_eq!(responding_servers, expected_servers);\n\n    drop(chan);\n\n    for lis in listeners {\n        lis.close().await;\n    }\n}\n\nasync fn run_rpc(chan: &Channel) -> String {\n    let (mut tx, mut rx) = chan\n        .invoke(\n            RequestHeaders::new().with_method_name(\"/some/method\"),\n            CallOptions::default(),\n        )\n        .await;\n\n    tokio::spawn(async move {\n        let reqs = vec![\n            MyReqMessage(\"My Request 1\".to_string()),\n            MyReqMessage(\"My Request 2\".to_string()),\n            MyReqMessage(\"My Request 3\".to_string()),\n        ];\n\n        for req in reqs {\n            tx.send(&req, client::SendOptions::default()).await.unwrap();\n        }\n    });\n\n    let mut server_id = String::new();\n    loop {\n        let mut res = MyResMessage::default();\n        match rx.next(&mut res).await {\n            ClientResponseStreamItem::Headers(_) => continue,\n            ClientResponseStreamItem::Message(_) => {\n                println!(\"CALL RESPONSE: {}\", res.0);\n                if let Some(id) = res\n                    .0\n                    .strip_prefix(\"Server \")\n                    .and_then(|s| s.split(':').next())\n                {\n                    server_id = id.to_string();\n                }\n            }\n            ClientResponseStreamItem::Trailers(_) => break,\n            ClientResponseStreamItem::StreamClosed => break,\n        }\n    }\n    server_id\n}\n"
  },
  {
    "path": "grpc/proto/echo/echo.proto",
    "content": "/*\n *\n * Copyright 2018 gRPC authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nsyntax = \"proto3\";\n\npackage grpc.examples.echo;\n\n// EchoRequest is the request for echo.\nmessage EchoRequest {\n  string message = 1;\n}\n\n// EchoResponse is the response for echo.\nmessage EchoResponse {\n  string message = 1;\n}\n\n// Echo is the echo service.\nservice Echo {\n  // UnaryEcho is unary echo.\n  rpc UnaryEcho(EchoRequest) returns (EchoResponse) {}\n  // ServerStreamingEcho is server side streaming.\n  rpc ServerStreamingEcho(EchoRequest) returns (stream EchoResponse) {}\n  // ClientStreamingEcho is client side streaming.\n  rpc ClientStreamingEcho(stream EchoRequest) returns (EchoResponse) {}\n  // BidirectionalStreamingEcho is bidi streaming.\n  rpc BidirectionalStreamingEcho(stream EchoRequest) returns (stream EchoResponse) {}\n}\n"
  },
  {
    "path": "grpc/src/attributes/linked_list.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::collections::BTreeSet;\nuse std::sync::Arc;\n\n/// A node in the persistent linked list.\n///\n/// Each node points to the previous state of the list.\n#[derive(Clone, Debug)]\nstruct Node<K, V> {\n    key: K,\n    value: V,\n    parent: Option<Arc<Node<K, V>>>,\n}\n\n/// A persistent linked list that behaves like a map.\n///\n/// This list is persistent, meaning that modifying it returns a new version of\n/// the list, while preserving the old version. It uses structural sharing to\n/// minimize memory usage.\n///\n/// The list supports shadowing: adding a key that already exists will effectively\n/// update the value for that key in the new version of the list.\n///\n/// # Warning\n///\n/// This list is intended to store a small number of values (few hundreds) and\n/// is optimized for memory usage. It is **not** optimized for query speed.\n#[derive(Debug)]\npub(crate) struct LinkedList<K, V> {\n    head: Option<Arc<Node<K, V>>>,\n}\n\nimpl<K, V> Clone for LinkedList<K, V> {\n    fn clone(&self) -> Self {\n        Self {\n            head: self.head.clone(),\n        }\n    }\n}\n\nimpl<K, V> Default for LinkedList<K, V> {\n    fn default() -> Self {\n        Self { head: None }\n    }\n}\n\nimpl<K, V> LinkedList<K, V> {\n    /// Creates a new, empty list.\n    pub(crate) fn new() -> Self {\n        Self::default()\n    }\n\n    /// Adds a key-value pair to the front of the list.\n    ///\n    /// If the key already exists in the list, this new entry will shadow the\n    /// old one, effectively updating the value.\n    pub(crate) fn add(&self, key: K, value: V) -> Self {\n        LinkedList {\n            head: Some(Arc::new(Node {\n                key,\n                value,\n                parent: self.head.clone(),\n            })),\n        }\n    }\n}\n\nimpl<K: Eq, V> LinkedList<K, V> {\n    /// Gets the value associated with the given key.\n    ///\n    /// This method iterates through the list from the front to find the most recent\n    /// entry for the key. If a deletion marker is encountered for the key, `None`\n    /// is returned.\n    ///\n    /// # Arguments\n    ///\n    /// * `key` - The key to look up.\n    ///\n    /// # Returns\n    ///\n    /// The value associated with the key, or `None` if the key is not present or\n    /// has been removed.\n    pub(crate) fn get(&self, key: &K) -> Option<&V> {\n        let mut current = self.head.as_ref();\n        while let Some(node) = current {\n            if &node.key == key {\n                return Some(&node.value);\n            }\n            current = node.parent.as_ref();\n        }\n        None\n    }\n}\n\nimpl<K: Ord, V> LinkedList<K, V> {\n    /// Returns an iterator over the key-value pairs in the list.\n    ///\n    /// The iterator yields unique keys. If a key has been added multiple times,\n    /// only the most recent value is returned. Keys that have been removed are\n    /// skipped.\n    pub(crate) fn iter(&self) -> Iter<'_, K, V> {\n        Iter {\n            current: self.head.as_ref(),\n            seen: BTreeSet::new(),\n        }\n    }\n}\n\n/// An iterator over the items of a `LinkedList`.\npub struct Iter<'a, K, V> {\n    current: Option<&'a Arc<Node<K, V>>>,\n    seen: BTreeSet<&'a K>,\n}\n\nimpl<'a, K: Ord, V> Iterator for Iter<'a, K, V> {\n    type Item = (&'a K, &'a V);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        loop {\n            let node = self.current?;\n            self.current = node.parent.as_ref();\n            if self.seen.insert(&node.key) {\n                return Some((&node.key, &node.value));\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_add_and_iter() {\n        let l = LinkedList::new().add(1, \"a\").add(2, \"b\").add(3, \"c\");\n        let v: Vec<_> = l.iter().map(|(k, v)| (*k, *v)).collect();\n        assert_eq!(v, vec![(3, \"c\"), (2, \"b\"), (1, \"a\")]);\n    }\n\n    #[test]\n    fn test_persistence() {\n        let l1 = LinkedList::new().add(1, \"a\");\n        let l2 = l1.add(2, \"b\");\n\n        // l1 should be unchanged\n        let v1: Vec<_> = l1.iter().map(|(k, v)| (*k, *v)).collect();\n        assert_eq!(v1, vec![(1, \"a\")]);\n\n        // l2 should have both\n        let v2: Vec<_> = l2.iter().map(|(k, v)| (*k, *v)).collect();\n        assert_eq!(v2, vec![(2, \"b\"), (1, \"a\")]);\n    }\n\n    #[test]\n    fn test_shadowing() {\n        let l = LinkedList::new().add(1, \"a\").add(1, \"b\");\n        let v: Vec<_> = l.iter().map(|(k, v)| (*k, *v)).collect();\n        // Should return the most recently added value for key 1\n        assert_eq!(v, vec![(1, \"b\")]);\n    }\n\n    #[test]\n    fn test_send_sync() {\n        fn assert_send_sync<T: Send + Sync>() {}\n        assert_send_sync::<LinkedList<i32, i32>>();\n    }\n}\n"
  },
  {
    "path": "grpc/src/attributes/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::any::Any;\nuse std::any::TypeId;\nuse std::cmp::Ordering;\nuse std::fmt::Debug;\n\nuse crate::attributes::linked_list::LinkedList;\n\nmod linked_list;\n\n/// Ensures only types that support comparison can be inserted into the\n/// Attributes struct. This allows the use of value-based equality rather than\n/// relying on pointer comparisons.\ntrait AttributeTrait: Any + Send + Sync + Debug {\n    fn any_ref(&self) -> &dyn Any;\n    fn dyn_eq(&self, other: &dyn AttributeTrait) -> bool;\n    fn dyn_cmp(&self, other: &dyn AttributeTrait) -> Ordering;\n}\n\nimpl<T: Any + Send + Sync + Eq + Ord + Debug> AttributeTrait for T {\n    fn any_ref(&self) -> &dyn Any {\n        self\n    }\n\n    fn dyn_eq(&self, other: &dyn AttributeTrait) -> bool {\n        if let Some(other) = other.any_ref().downcast_ref::<T>() {\n            self == other\n        } else {\n            false\n        }\n    }\n\n    fn dyn_cmp(&self, other: &dyn AttributeTrait) -> Ordering {\n        if let Some(other) = other.any_ref().downcast_ref::<T>() {\n            self.cmp(other)\n        } else {\n            // Fallback for safety, though map structure guarantees same-type\n            // comparison.\n            TypeId::of::<T>().cmp(&other.any_ref().type_id())\n        }\n    }\n}\n\n#[derive(Debug)]\nstruct AttributeValue {\n    inner: Box<dyn AttributeTrait>,\n}\n\nimpl PartialEq for AttributeValue {\n    fn eq(&self, other: &Self) -> bool {\n        self.inner.dyn_eq(other.inner.as_ref())\n    }\n}\n\nimpl Eq for AttributeValue {}\n\nimpl PartialOrd for AttributeValue {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for AttributeValue {\n    fn cmp(&self, other: &Self) -> Ordering {\n        self.inner.dyn_cmp(other.inner.as_ref())\n    }\n}\n\n/// A collection of attributes indexed by their type.\n///\n/// `Attributes` provides a map-like interface where values are keyed by their\n/// TypeId.\n///\n/// Equality and ordering of `Attributes` are structural.\n/// This means two `Attributes` maps are equal if they contain the same set of\n/// values, compared by value (via `Eq` trait).\n/// Stored types must implement `Any + Send + Sync + Eq + Ord + Debug`.\n///\n/// # Warning\n///\n/// This collection is intended to store a small number of values (few hundreds)\n/// and is optimized for memory usage. It is **not** optimized for query speed.\n#[derive(Clone, Default, Debug)]\npub struct Attributes {\n    elements: LinkedList<TypeId, AttributeValue>,\n}\n\nimpl Attributes {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Adds a value to the attributes.\n    /// Returns a new Attributes object with the value added.\n    /// If a value of the same type already exists, it is replaced.\n    pub fn add<T: Send + Sync + Eq + Ord + Debug + 'static>(&self, value: T) -> Self {\n        let id = TypeId::of::<T>();\n        Attributes {\n            elements: self.elements.add(\n                id,\n                AttributeValue {\n                    inner: Box::new(value),\n                },\n            ),\n        }\n    }\n\n    /// Gets a reference to a value of type T.\n    pub fn get<T: 'static>(&self) -> Option<&T> {\n        let id = TypeId::of::<T>();\n        self.elements\n            .get(&id)\n            .and_then(|v| v.inner.any_ref().downcast_ref())\n    }\n}\n\nimpl PartialEq for Attributes {\n    fn eq(&self, other: &Self) -> bool {\n        let mut v1: Vec<_> = self.elements.iter().collect();\n        let mut v2: Vec<_> = other.elements.iter().collect();\n        if v1.len() != v2.len() {\n            return false;\n        }\n        v1.sort();\n        v2.sort();\n        v1 == v2\n    }\n}\n\nimpl Eq for Attributes {}\n\nimpl PartialOrd for Attributes {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for Attributes {\n    fn cmp(&self, other: &Self) -> Ordering {\n        let mut v1: Vec<_> = self.elements.iter().collect();\n        let mut v2: Vec<_> = other.elements.iter().collect();\n        v1.sort();\n        v2.sort();\n        v1.cmp(&v2)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_eq() {\n        let a1 = Attributes::new().add(10i32);\n        let a2 = a1.clone();\n        let a3 = Attributes::new().add(10i32); // Structural equality\n\n        assert_eq!(a1, a2);\n        assert_eq!(a1, a3); // Now equal because 10 == 10\n\n        let a4 = Attributes::new().add(10i32).add(\"foo\".to_string());\n        assert_ne!(a1, a4);\n    }\n\n    #[test]\n    fn test_attributes() {\n        let attrs = Attributes::new();\n        let attrs = attrs.add(42i32);\n        let attrs = attrs.add(\"hello\".to_string());\n\n        assert_eq!(attrs.get::<i32>(), Some(&42));\n        assert_eq!(attrs.get::<String>(), Some(&\"hello\".to_string()));\n        assert_eq!(attrs.get::<bool>(), None);\n    }\n\n    #[test]\n    fn test_persistence() {\n        let a1 = Attributes::new().add(10i32);\n        let a2 = a1.add(20u32);\n\n        assert_eq!(a1.get::<i32>(), Some(&10));\n        assert_eq!(a1.get::<u32>(), None);\n\n        assert_eq!(a2.get::<i32>(), Some(&10));\n        assert_eq!(a2.get::<u32>(), Some(&20));\n    }\n\n    #[test]\n    fn test_overwrite() {\n        let a1 = Attributes::new().add(10i32);\n        let a2 = a1.add(20i32);\n\n        assert_eq!(a1.get::<i32>(), Some(&10));\n        assert_eq!(a2.get::<i32>(), Some(&20));\n    }\n\n    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]\n    struct Priority {\n        weight: u64,\n        name: String,\n    }\n\n    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]\n    struct Config {\n        retries: u32,\n        timeout_ms: u64,\n    }\n\n    #[test]\n    fn test_custom_structs() {\n        let p = Priority {\n            weight: 123,\n            name: \"alice\".into(),\n        };\n        let config = Config {\n            retries: 3,\n            timeout_ms: 1000,\n        };\n\n        let attrs = Attributes::new().add(p.clone()).add(config.clone());\n\n        assert_eq!(attrs.get::<Priority>(), Some(&p));\n        assert_eq!(attrs.get::<Config>(), Some(&config));\n\n        // Test overwrite\n        let p2 = Priority {\n            weight: 456,\n            name: \"bob\".into(),\n        };\n        let attrs2 = attrs.add(p2.clone());\n\n        assert_eq!(attrs2.get::<Priority>(), Some(&p2));\n        assert_eq!(attrs2.get::<Config>(), Some(&config));\n\n        // original should be unchanged\n        assert_eq!(attrs.get::<Priority>(), Some(&p));\n    }\n}\n"
  },
  {
    "path": "grpc/src/byte_str.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse core::str;\nuse std::ops::Deref;\n\nuse bytes::Bytes;\n\n/// A cheaply cloneable and sliceable chunk of contiguous memory.\n#[derive(Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]\npub struct ByteStr {\n    // Invariant: bytes contains valid UTF-8\n    bytes: Bytes,\n}\n\nimpl Deref for ByteStr {\n    type Target = str;\n\n    #[inline]\n    fn deref(&self) -> &str {\n        let b: &[u8] = self.bytes.as_ref();\n        // The invariant of `bytes` is that it contains valid UTF-8 allows us\n        // to unwrap.\n        str::from_utf8(b).unwrap()\n    }\n}\n\nimpl From<String> for ByteStr {\n    #[inline]\n    fn from(src: String) -> ByteStr {\n        ByteStr {\n            // Invariant: src is a String so contains valid UTF-8.\n            bytes: Bytes::from(src),\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/channel.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse core::panic;\nuse std::any::Any;\nuse std::error::Error;\nuse std::mem;\nuse std::str::FromStr;\nuse std::sync::Arc;\nuse std::sync::Mutex;\nuse std::time::Duration;\nuse std::time::Instant;\nuse std::vec;\n\nuse serde_json::json;\nuse tokio::sync::Notify;\nuse tokio::sync::mpsc;\nuse tokio::sync::watch;\nuse url::Url; // NOTE: http::Uri requires non-empty authority portion of URI\n\nuse crate::attributes::Attributes;\nuse crate::client::CallOptions;\nuse crate::client::ConnectivityState;\nuse crate::client::DynInvoke;\nuse crate::client::DynRecvStream;\nuse crate::client::DynSendStream;\nuse crate::client::Invoke;\nuse crate::client::load_balancing::ExternalSubchannel;\nuse crate::client::load_balancing::GLOBAL_LB_REGISTRY;\nuse crate::client::load_balancing::LbPolicy;\nuse crate::client::load_balancing::LbPolicyBuilder;\nuse crate::client::load_balancing::LbPolicyOptions;\nuse crate::client::load_balancing::LbState;\nuse crate::client::load_balancing::ParsedJsonLbConfig;\nuse crate::client::load_balancing::PickResult;\nuse crate::client::load_balancing::Picker;\nuse crate::client::load_balancing::Subchannel;\nuse crate::client::load_balancing::SubchannelState;\nuse crate::client::load_balancing::WorkScheduler;\nuse crate::client::load_balancing::pick_first;\nuse crate::client::load_balancing::round_robin;\nuse crate::client::load_balancing::{self};\nuse crate::client::name_resolution::Address;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::client::name_resolution::global_registry;\nuse crate::client::name_resolution::{self};\nuse crate::client::service_config::LbPolicyType;\nuse crate::client::service_config::ServiceConfig;\nuse crate::client::subchannel::InternalSubchannel;\nuse crate::client::subchannel::InternalSubchannelPool;\nuse crate::client::subchannel::NopBackoff;\nuse crate::client::subchannel::SubchannelKey;\nuse crate::client::subchannel::SubchannelStateWatcher;\nuse crate::client::transport::GLOBAL_TRANSPORT_REGISTRY;\nuse crate::client::transport::TransportRegistry;\nuse crate::core::RequestHeaders;\nuse crate::credentials::ChannelCredentials;\nuse crate::credentials::dyn_wrapper::DynChannelCredentials;\nuse crate::rt;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\nuse crate::rt::default_runtime;\n\n#[non_exhaustive]\npub struct ChannelOptions {\n    pub transport_options: Attributes, // ?\n    pub override_authority: Option<String>,\n    pub connection_backoff: Option<TODO>,\n    pub default_service_config: Option<String>,\n    pub disable_proxy: bool,\n    pub disable_service_config_lookup: bool,\n    pub disable_health_checks: bool,\n    pub max_retry_memory: u32, // ?\n    pub idle_timeout: Duration,\n    // TODO: pub transport_registry: Option<TransportRegistry>,\n    // TODO: pub name_resolver_registry: Option<ResolverRegistry>,\n    // TODO: pub lb_policy_registry: Option<LbPolicyRegistry>,\n\n    // Typically we allow settings at the channel level that impact all RPCs,\n    // but can also be set per-RPC.  E.g.s:\n    //\n    // - interceptors\n    // - user-agent string override\n    // - max message sizes\n    // - max retry/hedged attempts\n    // - disable retry\n    //\n    // In gRPC-Go, we can express CallOptions as DialOptions, which is a nice\n    // pattern: https://pkg.go.dev/google.golang.org/grpc#WithDefaultCallOptions\n    //\n    // To do this in rust, all optional behavior for a request would need to be\n    // expressed through a trait that applies a mutation to a request.  We'd\n    // apply all those mutations before the user's options so the user's options\n    // would override the defaults, or so the defaults would occur first.\n    pub default_request_extensions: Vec<Box<TODO>>, // ??\n}\n\nimpl Default for ChannelOptions {\n    fn default() -> Self {\n        Self {\n            transport_options: Attributes::default(),\n            override_authority: None,\n            connection_backoff: None,\n            default_service_config: None,\n            disable_proxy: false,\n            disable_service_config_lookup: false,\n            disable_health_checks: false,\n            max_retry_memory: 8 * 1024 * 1024, // 8MB -- ???\n            idle_timeout: Duration::from_secs(30 * 60),\n            default_request_extensions: vec![],\n        }\n    }\n}\n\nimpl ChannelOptions {\n    pub fn transport_options(self, transport_options: TODO) -> Self {\n        todo!(); // add to existing options.\n    }\n    pub fn override_authority(self, authority: String) -> Self {\n        Self {\n            override_authority: Some(authority),\n            ..self\n        }\n    }\n    // etc\n}\n\n// All of Channel needs to be thread-safe.  Arc<inner>?  Or give out\n// Arc<Channel> from constructor?\n#[derive(Clone)]\npub struct Channel {\n    inner: Arc<PersistentChannel>,\n}\n\nimpl Channel {\n    /// Constructs a new gRPC channel.  A gRPC channel is a virtual, persistent\n    /// connection to a service.  Channel creation cannot fail, but if the\n    /// target string is invalid, the returned channel will never connect, and\n    /// will fail all RPCs.\n    // TODO: should this return a Result instead?\n    pub fn new<C>(target: &str, credentials: C, options: ChannelOptions) -> Self\n    where\n        C: ChannelCredentials,\n        C::Output<Box<dyn GrpcEndpoint>>: GrpcEndpoint + 'static,\n    {\n        pick_first::reg();\n        round_robin::reg();\n        Self {\n            inner: Arc::new(PersistentChannel::new(\n                target,\n                Box::new(credentials) as Box<dyn DynChannelCredentials>,\n                default_runtime(),\n                options,\n            )),\n        }\n    }\n\n    // TODO: enter_idle(&self) and graceful_stop()?\n\n    /// Returns the current state of the channel. If there is no underlying active channel,\n    /// returns Idle. If `connect` is true, will create a new active channel.\n    pub fn state(&mut self, connect: bool) -> ConnectivityState {\n        self.inner.state(connect)\n    }\n\n    /// Waits for the state of the channel to change from source.  Times out and\n    /// returns an error after the deadline.\n    pub async fn wait_for_state_change(\n        &self,\n        source: ConnectivityState,\n        deadline: Instant,\n    ) -> Result<(), Box<dyn Error>> {\n        todo!()\n    }\n}\n\nimpl Invoke for Channel {\n    type SendStream = Box<dyn DynSendStream>;\n    type RecvStream = Box<dyn DynRecvStream>;\n\n    async fn invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        let ac = self.inner.get_active_channel();\n        ac.invoke(headers, options).await\n    }\n}\n\n// A PersistentChannel represents the static configuration of a channel and an\n// optional Arc of an ActiveChannel.  An ActiveChannel exists whenever the\n// PersistentChannel is not IDLE.  Every channel is IDLE at creation, or after\n// some configurable timeout elapses without any any RPC activity.\nstruct PersistentChannel {\n    target: Url,\n    options: ChannelOptions,\n    active_channel: Mutex<Option<Arc<ActiveChannel>>>,\n    runtime: GrpcRuntime,\n}\n\nimpl PersistentChannel {\n    // Channels begin idle so `new()` does not automatically connect.\n    // ChannelOption contain only optional parameters.\n    fn new(\n        target: &str,\n        _credentials: Box<dyn DynChannelCredentials>,\n        runtime: GrpcRuntime,\n        options: ChannelOptions,\n    ) -> Self {\n        Self {\n            target: Url::from_str(target).unwrap(), // TODO handle err\n            active_channel: Mutex::default(),\n            options,\n            runtime,\n        }\n    }\n\n    /// Returns the current state of the channel. If there is no underlying active channel,\n    /// returns Idle. If `connect` is true, will create a new active channel iff none exists.\n    fn state(&self, connect: bool) -> ConnectivityState {\n        // Done this away to avoid potentially locking twice.\n        let active_channel = if connect {\n            self.get_active_channel()\n        } else {\n            match self.active_channel.lock().unwrap().clone() {\n                Some(x) => x,\n                None => {\n                    return ConnectivityState::Idle;\n                }\n            }\n        };\n\n        active_channel\n            .connectivity_state\n            .cur()\n            .unwrap_or(ConnectivityState::Idle)\n    }\n\n    /// Gets the underlying active channel. If there is no current connection, it will create one.\n    /// This cannot fail and will always return a valid active channel.\n    fn get_active_channel(&self) -> Arc<ActiveChannel> {\n        let mut active_channel = self.active_channel.lock().unwrap();\n\n        if active_channel.is_none() {\n            *active_channel = Some(ActiveChannel::new(\n                self.target.clone(),\n                &self.options,\n                self.runtime.clone(),\n            ));\n        }\n\n        active_channel.clone().unwrap() // We have ensured this is not None.\n    }\n}\n\nstruct ActiveChannel {\n    abort_handle: Box<dyn rt::TaskHandle>,\n    picker: Arc<Watcher<Arc<dyn Picker>>>,\n    connectivity_state: Arc<Watcher<ConnectivityState>>,\n    runtime: GrpcRuntime,\n}\n\nimpl ActiveChannel {\n    fn new(target: Url, options: &ChannelOptions, runtime: GrpcRuntime) -> Arc<Self> {\n        let (tx, mut rx) = mpsc::unbounded_channel::<WorkQueueItem>();\n        let transport_registry = GLOBAL_TRANSPORT_REGISTRY.clone();\n\n        let resolve_now = Arc::new(Notify::new());\n        let connectivity_state = Arc::new(Watcher::new());\n        let picker = Arc::new(Watcher::new());\n        let mut channel_controller = InternalChannelController::new(\n            transport_registry,\n            resolve_now.clone(),\n            tx.clone(),\n            picker.clone(),\n            connectivity_state.clone(),\n            runtime.clone(),\n        );\n\n        // TODO(arjan-bal): Return error here instead of panicking.\n        let rb = global_registry().get(target.scheme()).unwrap();\n        let target = name_resolution::Target::from(target);\n        let authority = target.authority_host_port();\n        let authority = if authority.is_empty() {\n            rb.default_authority(&target).to_owned()\n        } else {\n            authority\n        };\n        let work_scheduler = Arc::new(ResolverWorkScheduler { wqtx: tx });\n        let resolver_opts = name_resolution::ResolverOptions {\n            authority,\n            work_scheduler,\n            runtime: runtime.clone(),\n        };\n        let resolver = rb.build(&target, resolver_opts);\n\n        let jh = runtime.spawn(Box::pin(async move {\n            let mut resolver = resolver;\n            while let Some(w) = rx.recv().await {\n                match w {\n                    WorkQueueItem::Closure(func) => func(&mut channel_controller),\n                    WorkQueueItem::ScheduleResolver => resolver.work(&mut channel_controller),\n                }\n            }\n        }));\n\n        Arc::new(Self {\n            abort_handle: jh,\n            picker: picker.clone(),\n            connectivity_state: connectivity_state.clone(),\n            runtime,\n        })\n    }\n}\n\nimpl Invoke for Arc<ActiveChannel> {\n    type SendStream = Box<dyn DynSendStream>;\n    type RecvStream = Box<dyn DynRecvStream>;\n\n    async fn invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        let mut i = self.picker.iter();\n        loop {\n            if let Some(p) = i.next().await {\n                let result = &p.pick(&headers);\n                match result {\n                    PickResult::Pick(pr) => {\n                        if let Some(sc) = (pr.subchannel.as_ref() as &dyn Any)\n                            .downcast_ref::<ExternalSubchannel>()\n                        {\n                            return sc\n                                .isc\n                                .as_ref()\n                                .unwrap()\n                                .dyn_invoke(headers, options.clone())\n                                .await;\n                        } else {\n                            panic!(\n                                \"picked subchannel is not an implementation provided by the channel\"\n                            );\n                        }\n                    }\n                    PickResult::Queue => {\n                        // Continue and retry the RPC with the next picker.\n                    }\n                    PickResult::Fail(status) => {\n                        todo!(\"failed pick: {:?}\", status);\n                    }\n                    PickResult::Drop(status) => {\n                        todo!(\"dropped pick: {:?}\", status);\n                    }\n                }\n            }\n        }\n    }\n}\n\nimpl Drop for ActiveChannel {\n    fn drop(&mut self) {\n        self.abort_handle.abort();\n    }\n}\n\nstruct ResolverWorkScheduler {\n    wqtx: WorkQueueTx,\n}\n\npub(super) type WorkQueueTx = mpsc::UnboundedSender<WorkQueueItem>;\n\nimpl name_resolution::WorkScheduler for ResolverWorkScheduler {\n    fn schedule_work(&self) {\n        let _ = self.wqtx.send(WorkQueueItem::ScheduleResolver);\n    }\n}\n\npub(crate) struct InternalChannelController {\n    pub(super) lb: Arc<LbController>, // called and passes mutable parent to it, so must be Arc.\n    transport_registry: TransportRegistry,\n    pub(super) subchannel_pool: Arc<InternalSubchannelPool>,\n    resolve_now: Arc<Notify>,\n    wqtx: WorkQueueTx,\n    lb_work_scheduler: Arc<LbWorkScheduler>,\n    picker: Arc<Watcher<Arc<dyn Picker>>>,\n    connectivity_state: Arc<Watcher<ConnectivityState>>,\n    runtime: GrpcRuntime,\n}\n\nimpl InternalChannelController {\n    fn new(\n        transport_registry: TransportRegistry,\n        resolve_now: Arc<Notify>,\n        wqtx: WorkQueueTx,\n        picker: Arc<Watcher<Arc<dyn Picker>>>,\n        connectivity_state: Arc<Watcher<ConnectivityState>>,\n        runtime: GrpcRuntime,\n    ) -> Self {\n        let lb_work_scheduler = Arc::new(LbWorkScheduler {\n            wqtx: wqtx.clone(),\n            pending: Mutex::default(),\n        });\n        let lb = Arc::new(LbController::new(\n            lb_work_scheduler.clone(),\n            runtime.clone(),\n        ));\n\n        Self {\n            lb,\n            transport_registry,\n            subchannel_pool: Arc::new(InternalSubchannelPool::new()),\n            resolve_now,\n            wqtx,\n            picker,\n            connectivity_state,\n            runtime,\n            lb_work_scheduler,\n        }\n    }\n\n    fn new_esc_for_isc(&self, isc: Arc<InternalSubchannel>) -> Arc<dyn Subchannel> {\n        let sc = Arc::new(ExternalSubchannel::new(isc.clone(), self.wqtx.clone()));\n        let watcher = Arc::new(SubchannelStateWatcher::new(sc.clone(), self.wqtx.clone()));\n        sc.set_watcher(watcher.clone());\n        isc.register_connectivity_state_watcher(watcher.clone());\n        sc\n    }\n}\n\nimpl name_resolution::ChannelController for InternalChannelController {\n    fn update(&mut self, update: ResolverUpdate) -> Result<(), String> {\n        let lb = self.lb.clone();\n        lb.handle_resolver_update(update, self)\n            .map_err(|err| err.to_string())\n    }\n\n    fn parse_service_config(&self, config: &str) -> Result<ServiceConfig, String> {\n        Err(\"service configs not supported\".to_string())\n    }\n}\n\nimpl load_balancing::ChannelController for InternalChannelController {\n    fn new_subchannel(&mut self, address: &Address) -> Arc<dyn Subchannel> {\n        let key = SubchannelKey::new(address.clone());\n        if let Some(isc) = self.subchannel_pool.lookup_subchannel(&key) {\n            return self.new_esc_for_isc(isc);\n        }\n\n        // If we get here, it means one of two things:\n        // 1. provided key is not found in the map\n        // 2. provided key points to an unpromotable value, which can occur if\n        //    its internal subchannel has been dropped but hasn't been\n        //    unregistered yet.\n\n        let transport = self\n            .transport_registry\n            .get_transport(address.network_type)\n            .unwrap();\n        let scp = self.subchannel_pool.clone();\n        let isc = InternalSubchannel::new(\n            key.clone(),\n            transport,\n            Arc::new(NopBackoff {}),\n            Box::new(move |k: SubchannelKey| {\n                scp.unregister_subchannel(&k);\n            }),\n            self.runtime.clone(),\n        );\n        let _ = self.subchannel_pool.register_subchannel(&key, isc.clone());\n        self.new_esc_for_isc(isc)\n    }\n\n    fn update_picker(&mut self, update: LbState) {\n        println!(\n            \"update picker called with state: {:?}\",\n            update.connectivity_state\n        );\n        self.picker.update(update.picker);\n        self.connectivity_state.update(update.connectivity_state);\n    }\n\n    fn request_resolution(&mut self) {\n        self.resolve_now.notify_one();\n    }\n}\n\n// A channel that is not idle (connecting, ready, or erroring).\n#[derive(Debug)]\npub(super) struct LbController {\n    pub(super) policy: Mutex<Option<Box<dyn LbPolicy>>>,\n    policy_builder: Mutex<Option<Arc<dyn LbPolicyBuilder>>>,\n    runtime: GrpcRuntime,\n    work_scheduler: Arc<LbWorkScheduler>,\n}\n\n#[derive(Debug)]\nstruct LbWorkScheduler {\n    pending: Mutex<bool>,\n    wqtx: WorkQueueTx,\n}\n\nimpl WorkScheduler for LbWorkScheduler {\n    fn schedule_work(&self) {\n        if mem::replace(&mut *self.pending.lock().unwrap(), true) {\n            // Already had a pending call scheduled.\n            return;\n        }\n        let _ = self.wqtx.send(WorkQueueItem::Closure(Box::new(\n            |c: &mut InternalChannelController| {\n                *c.lb_work_scheduler.pending.lock().unwrap() = false;\n                c.lb.clone()\n                    .policy\n                    .lock()\n                    .unwrap()\n                    .as_mut()\n                    .unwrap()\n                    .work(c);\n            },\n        )));\n    }\n}\n\nimpl LbController {\n    fn new(work_scheduler: Arc<LbWorkScheduler>, runtime: GrpcRuntime) -> Self {\n        Self {\n            policy_builder: Mutex::default(),\n            policy: Mutex::default(), // new(None::<Box<dyn LbPolicy>>),\n            work_scheduler,\n            runtime,\n        }\n    }\n\n    fn handle_resolver_update(\n        self: &Arc<Self>,\n        update: ResolverUpdate,\n        controller: &mut InternalChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        let mut policy_name = pick_first::POLICY_NAME;\n        if let Ok(Some(service_config)) = update.service_config.as_ref()\n            && service_config\n                .load_balancing_policy\n                .as_ref()\n                .is_some_and(|p| *p == LbPolicyType::RoundRobin)\n        {\n            policy_name = round_robin::POLICY_NAME;\n        }\n        let mut p = self.policy.lock().unwrap();\n        if p.is_none() {\n            let builder = GLOBAL_LB_REGISTRY.get_policy(policy_name).unwrap();\n            let newpol = builder.build(LbPolicyOptions {\n                work_scheduler: self.work_scheduler.clone(),\n                runtime: self.runtime.clone(),\n            });\n            *self.policy_builder.lock().unwrap() = Some(builder);\n            *p = Some(newpol);\n        }\n\n        // TODO: config should come from ServiceConfig.\n        let builder = self.policy_builder.lock().unwrap();\n        let config = match builder\n            .as_ref()\n            .unwrap()\n            .parse_config(&ParsedJsonLbConfig::from_value(\n                json!({\"shuffleAddressList\": true, \"unknown_field\": false}),\n            )) {\n            Ok(cfg) => cfg,\n            Err(e) => {\n                return Err(e);\n            }\n        };\n\n        p.as_mut()\n            .unwrap()\n            .resolver_update(update, config.as_ref(), controller)\n\n        // TODO: close old LB policy gracefully vs. drop?\n    }\n    pub(super) fn subchannel_update(\n        &self,\n        subchannel: Arc<dyn Subchannel>,\n        state: &SubchannelState,\n        channel_controller: &mut dyn load_balancing::ChannelController,\n    ) {\n        let mut p = self.policy.lock().unwrap();\n\n        p.as_mut()\n            .unwrap()\n            .subchannel_update(subchannel, state, channel_controller);\n    }\n}\n\npub(super) enum WorkQueueItem {\n    // Execute the closure.\n    Closure(Box<dyn FnOnce(&mut InternalChannelController) + Send + Sync>),\n    // Call the resolver to do work.\n    ScheduleResolver,\n}\n\npub struct TODO;\n\n// Enables multiple receivers to view data output from a single producer.\n// Producer calls update.  Consumers call iter() and call next() until they find\n// a good value or encounter None.\npub(crate) struct Watcher<T> {\n    tx: watch::Sender<Option<T>>,\n    rx: watch::Receiver<Option<T>>,\n}\n\nimpl<T: Clone> Watcher<T> {\n    fn new() -> Self {\n        let (tx, rx) = watch::channel(None);\n        Self { tx, rx }\n    }\n\n    pub(crate) fn iter(&self) -> WatcherIter<T> {\n        let mut rx = self.rx.clone();\n        rx.mark_changed();\n        WatcherIter { rx }\n    }\n\n    pub(crate) fn cur(&self) -> Option<T> {\n        let mut rx = self.rx.clone();\n        rx.mark_changed();\n        let c = rx.borrow();\n        c.clone()\n    }\n\n    fn update(&self, item: T) {\n        self.tx.send(Some(item)).unwrap();\n    }\n}\n\npub(crate) struct WatcherIter<T> {\n    rx: watch::Receiver<Option<T>>,\n}\n// TODO: Use an arc_swap::ArcSwap instead that contains T and a channel closed\n// when T is updated.  Even if the channel needs a lock, the fast path becomes\n// lock-free.\n\nimpl<T: Clone> WatcherIter<T> {\n    /// Returns the next unseen value\n    pub(crate) async fn next(&mut self) -> Option<T> {\n        loop {\n            self.rx.changed().await.ok()?;\n            let x = self.rx.borrow_and_update();\n            if x.is_some() {\n                return x.clone();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/interceptor.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse crate::client::CallOptions;\nuse crate::client::Invoke;\nuse crate::client::InvokeOnce;\nuse crate::client::RecvStream;\nuse crate::client::SendStream;\nuse crate::core::RequestHeaders;\n\n/// A trait which allows intercepting an RPC invoke operation.  The trait is\n/// generic on I which should either be implemented as InvokeOnce (for\n/// interceptors that only need to call next once) or Invoke[+Clone+'static]\n/// (for interceptors that need to call next multiple times).\n#[trait_variant::make(Send)]\npub trait Intercept<I>: Sync {\n    type SendStream: SendStream + 'static;\n    type RecvStream: RecvStream + 'static;\n\n    /// Intercepts the start of a call.  Implementations should generally use\n    /// next to create and start a call whose streams are optionally wrapped\n    /// before being returned.\n    async fn intercept(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n        next: I,\n    ) -> (Self::SendStream, Self::RecvStream);\n}\n\n/// Like Intercept, but not reusable.\n#[trait_variant::make(Send)]\npub trait InterceptOnce<I>: Sync {\n    type SendStream: SendStream + 'static;\n    type RecvStream: RecvStream + 'static;\n\n    /// Intercepts the start of a call.  Implementations should generally use\n    /// next to create and start a call whose streams are optionally wrapped\n    /// before being returned.\n    async fn intercept_once(\n        self,\n        headers: RequestHeaders,\n        options: CallOptions,\n        next: I,\n    ) -> (Self::SendStream, Self::RecvStream);\n}\n\n/// Wraps an interceptor that implements Intercept, and implements InterceptOnce\n/// instead, allowing it to be paired with a non-reusable Invoke implementation\n/// inside an `Intercepted` struct.\n#[derive(Clone)]\npub struct IntoOnce<T>(pub T);\n\nimpl<I, T: Send + Sync, SS, RS> InterceptOnce<I> for IntoOnce<T>\nwhere\n    I: InvokeOnce,\n    SS: SendStream + 'static,\n    RS: RecvStream + 'static,\n    T: Intercept<I, SendStream = SS, RecvStream = RS>,\n{\n    type SendStream = SS;\n    type RecvStream = RS;\n\n    async fn intercept_once(\n        self,\n        headers: RequestHeaders,\n        options: CallOptions,\n        next: I,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        self.0.intercept(headers, options, next).await\n    }\n}\n\n/// Wraps `Invoke` and `Intercept` impls and implements `Invoke` for the\n/// combination.  Or wraps `InvokeOnce` and `InterceptOnce<InvokeOnce>` impls\n/// and implements `InvokeOnce` for the combination.\n#[derive(Clone, Copy)]\npub struct Intercepted<Inv, Int> {\n    invoke: Inv,\n    intercept: Int,\n}\n\nimpl<Inv, Int> Intercepted<Inv, Int> {\n    pub fn new(invoke: Inv, intercept: Int) -> Self {\n        Self { invoke, intercept }\n    }\n}\n\nimpl<Inv, Int> InvokeOnce for Intercepted<Inv, Int>\nwhere\n    Inv: InvokeOnce,\n    Int: InterceptOnce<Inv>,\n{\n    type SendStream = Int::SendStream;\n    type RecvStream = Int::RecvStream;\n\n    async fn invoke_once(\n        self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        self.intercept\n            .intercept_once(headers, options, self.invoke)\n            .await\n    }\n}\n\nimpl<Inv, Int, SS, RS> Invoke for Intercepted<Inv, Int>\nwhere\n    Inv: Send + Sync,\n    for<'a> Int: Send + Sync + Intercept<&'a Inv, SendStream = SS, RecvStream = RS>,\n    SS: SendStream + 'static,\n    RS: RecvStream + 'static,\n{\n    type SendStream = SS;\n    type RecvStream = RS;\n\n    async fn invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        self.intercept\n            .intercept(headers, options, &self.invoke)\n            .await\n    }\n}\n\n/// Combines an `Invoke` with an `InterceptOnce` to implement `InvokeOnce`.\npub struct InterceptedOnce<Inv, Int> {\n    invoke: Inv,\n    intercept: Int,\n}\n\nimpl<Inv, Int> InterceptedOnce<Inv, Int> {\n    pub fn new(invoke: Inv, intercept: Int) -> Self {\n        Self { invoke, intercept }\n    }\n}\n\nimpl<Inv, Int, SS, RS> InvokeOnce for InterceptedOnce<Inv, Int>\nwhere\n    Inv: Send + Sync,\n    for<'a> Int: InterceptOnce<&'a Inv, SendStream = SS, RecvStream = RS>,\n    SS: SendStream + 'static,\n    RS: RecvStream + 'static,\n{\n    type SendStream = SS;\n    type RecvStream = RS;\n\n    async fn invoke_once(\n        self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        self.intercept\n            .intercept_once(headers, options, &self.invoke)\n            .await\n    }\n}\n\n/// Implements methods for combining `Invoke` implementations with either\n/// `Intercept` or `InterceptOnce` interceptors.  Blanket implemented on any\n/// `Invoke`.\npub trait InvokeExt: Invoke + Sized {\n    fn with_interceptor<Int>(self, interceptor: Int) -> Intercepted<Self, Int>\n    where\n        for<'a> Int: Intercept<&'a Self>,\n    {\n        Intercepted::new(self, interceptor)\n    }\n\n    fn with_once_interceptor<Int>(self, interceptor: Int) -> InterceptedOnce<Self, Int>\n    where\n        for<'a> Int: InterceptOnce<&'a Self>,\n    {\n        InterceptedOnce::new(self, interceptor)\n    }\n}\n\n/// Implements methods for combining `InvokeOnce` implementations with\n/// `Intercept<InvokeOnce>` or `InterceptOnce<InvokeOnce>` interceptors.\n/// Blanket implemented on any `InvokeOnce`.\npub trait InvokeOnceExt: InvokeOnce + Sized {\n    fn with_interceptor<Int>(self, interceptor: Int) -> Intercepted<Self, IntoOnce<Int>>\n    where\n        for<'a> Int: Intercept<Self>,\n    {\n        Intercepted::new(self, IntoOnce(interceptor))\n    }\n\n    fn with_once_interceptor<Int>(self, interceptor: Int) -> Intercepted<Self, Int>\n    where\n        Int: InterceptOnce<Self>,\n    {\n        Intercepted::new(self, interceptor)\n    }\n}\n\nimpl<T: Invoke + Sized> InvokeExt for T {}\nimpl<T: InvokeOnce + Sized> InvokeOnceExt for T {}\n\n// Tests for Intercepted and InterceptedOnce and examples of the four types of\n// interceptors, how they are implemented, and how they are combined with\n// Invoke/InvokeOnce.\n//\n// The four different kinds of interceptors are:\n//\n// 1. Reusable: uses `next` once.\n//    impl Intercept<InvokeOnce>\n//\n// 2. ResuableFanOut: uses `next` multiple times.\n//    impl Intercept<&Invoke [+ Clone + 'static if needed]>\n//\n// 3. Oneshot: uses `next` once.\n//    impl InterceptOnce<InvokeOnce>\n//\n// 4. OneshotFanOut: uses `next` multiple times.\n//    impl InterceptOnce<&Invoke [+ Clone + 'static if needed]>\n//\n// Examples of each of these are defined below.\n#[cfg(test)]\nmod test {\n    use std::future::Future;\n    use std::sync::Arc;\n\n    use bytes::Buf;\n    use bytes::Bytes;\n    use tokio::pin;\n    use tokio::select;\n    use tokio::sync::Mutex;\n    use tokio::sync::Notify;\n    use tokio::sync::broadcast;\n    use tokio::sync::mpsc;\n    use tokio::task;\n\n    use super::*;\n    use crate::Status;\n    use crate::StatusCode;\n    use crate::client::CallOptions;\n    use crate::client::Invoke;\n    use crate::client::RecvStream;\n    use crate::client::SendOptions;\n    use crate::client::SendStream;\n    use crate::core::ClientResponseStreamItem;\n    use crate::core::RecvMessage;\n    use crate::core::ResponseHeaders;\n    use crate::core::SendMessage;\n    use crate::core::Trailers;\n\n    #[derive(Clone)]\n    struct Reusable;\n    impl<I: InvokeOnce> Intercept<I> for Reusable {\n        type SendStream = NopStream;\n        type RecvStream = I::RecvStream;\n\n        async fn intercept(\n            &self,\n            headers: RequestHeaders,\n            args: CallOptions,\n            next: I,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            let (_, rx) = next.invoke_once(headers, args).await;\n            (NopStream, rx)\n        }\n    }\n\n    #[derive(Clone)]\n    struct ReusableFanOut;\n    impl<I: Invoke + Clone + 'static> Intercept<&I> for ReusableFanOut {\n        type SendStream = RetrySendStream<I::SendStream>;\n        type RecvStream = RetryRecvStream<I>;\n\n        async fn intercept(\n            &self,\n            headers: RequestHeaders,\n            args: CallOptions,\n            next: &I,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            start_retry_streams(next, headers, args).await\n        }\n    }\n    struct Oneshot;\n    impl<I: InvokeOnce> InterceptOnce<I> for Oneshot {\n        type SendStream = I::SendStream;\n        type RecvStream = NopStream;\n\n        async fn intercept_once(\n            self,\n            headers: RequestHeaders,\n            args: CallOptions,\n            next: I,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            let (tx, _) = next.invoke_once(headers, args).await;\n            (tx, NopStream)\n        }\n    }\n\n    struct OneshotFanOut;\n    impl<I: Invoke + Clone> InterceptOnce<&I> for OneshotFanOut {\n        type SendStream = I::SendStream;\n        type RecvStream = I::RecvStream;\n\n        async fn intercept_once(\n            self,\n            headers: RequestHeaders,\n            args: CallOptions,\n            next: &I,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            let (_, _) = next.invoke(headers.clone(), args.clone()).await;\n            next.invoke(headers, args).await\n        }\n    }\n\n    // Tests all 6 valid scenarios combining an invoker with an interceptor.\n    #[tokio::test]\n    async fn test_interceptor_creation() {\n        // Reusable Invoke with resuable Intercept.\n        {\n            let i = NopInvoker.with_interceptor(Reusable);\n            i.invoke(RequestHeaders::default(), CallOptions::default())\n                .await;\n            // Since Invoke is implemented on &Intercepted, it is reusable.\n            i.invoke(RequestHeaders::default(), CallOptions::default())\n                .await;\n        }\n\n        // One-shot Invoke with resuable Intercept.\n        {\n            let i = NopOnceInvoker.with_interceptor(Reusable);\n            i.invoke_once(RequestHeaders::default(), CallOptions::default())\n                .await;\n        }\n\n        // Reusable Invoke with resuable fan-out Intercept.\n        {\n            let i = NopInvoker.with_interceptor(ReusableFanOut);\n            i.invoke(RequestHeaders::default(), CallOptions::default())\n                .await;\n            // Since Invoke is implemented on &Intercepted, it is reusable.\n            i.invoke(RequestHeaders::default(), CallOptions::default())\n                .await;\n        }\n\n        // One-shot Invoke with fan-out Intercept is illegal.\n\n        // Reusable Invoke with one-shot Intercept.\n        {\n            let i = NopInvoker.with_once_interceptor(Oneshot);\n            i.invoke_once(RequestHeaders::default(), CallOptions::default())\n                .await;\n        }\n\n        // One-shot Invoke with one-shot Intercept.\n        {\n            let i = NopOnceInvoker.with_once_interceptor(Oneshot);\n            i.invoke_once(RequestHeaders::default(), CallOptions::default())\n                .await;\n        }\n\n        // Reusable Invoke with one-shot fan-out Intercept.\n        {\n            let i = NopInvoker.with_once_interceptor(OneshotFanOut);\n            i.invoke_once(RequestHeaders::default(), CallOptions::default())\n                .await;\n        }\n\n        // One-shot Invoke with one-shot fan-out Intercept is illegal.\n    }\n\n    // Tests that a a retry interceptor retries cached send operations and\n    // ultimately completes with success on an OK response.\n    #[tokio::test]\n    async fn test_retry_interceptor_succeeds() {\n        let (invoker, mut controller) = MockInvoker::new();\n        let chan = invoker.with_interceptor(ReusableFanOut);\n        let (mut tx, mut rx) = chan\n            .invoke(RequestHeaders::default(), CallOptions::default())\n            .await;\n        let one = Bytes::from(vec![1]);\n        let two = Bytes::from(vec![2]);\n        tx.send(&ByteSendMsg::new(&one), SendOptions::default())\n            .await\n            .unwrap();\n        assert_eq!(controller.recv_req().await.0, one);\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(StatusCode::Internal, \"\"),\n            )))\n            .await;\n        let handle = task::spawn(async move { rx.next(&mut ByteRecvMsg::new()).await });\n        assert_eq!(controller.recv_req().await.0, one);\n        tx.send(&ByteSendMsg::new(&two), SendOptions::default())\n            .await\n            .unwrap();\n        assert_eq!(controller.recv_req().await.0, two);\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(StatusCode::Internal, \"\"),\n            )))\n            .await;\n        assert_eq!(controller.recv_req().await.0, one);\n        assert_eq!(controller.recv_req().await.0, two);\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(StatusCode::Ok, \"\"),\n            )))\n            .await;\n        let resp = handle.await.unwrap();\n        let ClientResponseStreamItem::Trailers(trailers) = resp else {\n            panic!(\"unexpected resp: {resp:?}\");\n        };\n        assert_eq!(trailers.status().code(), StatusCode::Ok);\n    }\n\n    // Tests that a a retry interceptor retries cached send operations but fails\n    // after the backing streams fail three times.\n    #[tokio::test]\n    async fn test_retry_interceptor_fails() {\n        let (invoker, mut controller) = MockInvoker::new();\n        let chan = invoker.with_interceptor(ReusableFanOut);\n        let (mut tx, mut rx) = chan\n            .invoke(RequestHeaders::default(), CallOptions::default())\n            .await;\n        let one = Bytes::from(vec![1]);\n        let two = Bytes::from(vec![2]);\n        tx.send(&ByteSendMsg::new(&one), SendOptions::default())\n            .await\n            .unwrap();\n        assert_eq!(controller.recv_req().await.0, one);\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(crate::StatusCode::Internal, \"\"),\n            )))\n            .await;\n        let handle = task::spawn(async move { rx.next(&mut ByteRecvMsg::new()).await });\n        assert_eq!(controller.recv_req().await.0, one);\n        tx.send(&ByteSendMsg::new(&two), SendOptions::default())\n            .await\n            .unwrap();\n        assert_eq!(controller.recv_req().await.0, two);\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(crate::StatusCode::Internal, \"\"),\n            )))\n            .await;\n        assert_eq!(controller.recv_req().await.0, one);\n        assert_eq!(controller.recv_req().await.0, two);\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(crate::StatusCode::Internal, \"\"),\n            )))\n            .await;\n        assert_eq!(controller.recv_req().await.0, one);\n        assert_eq!(controller.recv_req().await.0, two);\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(crate::StatusCode::Internal, \"\"),\n            )))\n            .await;\n        let resp = handle.await.unwrap();\n        let ClientResponseStreamItem::Trailers(trailers) = resp else {\n            panic!(\"unexpected resp: {resp:?}\");\n        };\n        assert_eq!(trailers.status().code(), crate::StatusCode::Internal);\n    }\n\n    // Tests that a a retry interceptor doesn't retry cached operations after\n    // receiving the headers from the server.\n    #[tokio::test]\n    async fn test_retry_interceptor_commit_on_headers() {\n        let (invoker, mut controller) = MockInvoker::new();\n        let chan = invoker.with_interceptor(ReusableFanOut);\n        let (mut tx, mut rx) = chan\n            .invoke(RequestHeaders::default(), CallOptions::default())\n            .await;\n        let one = Bytes::from(vec![1]);\n        tx.send(&ByteSendMsg::new(&one), SendOptions::default())\n            .await\n            .unwrap();\n        assert_eq!(controller.recv_req().await.0, one);\n        controller\n            .send_resp(ClientResponseStreamItem::Headers(ResponseHeaders::default()))\n            .await;\n\n        let resp = rx.next(&mut ByteRecvMsg::new()).await;\n        assert!(matches!(resp, ClientResponseStreamItem::Headers(_)));\n\n        controller\n            .send_resp(ClientResponseStreamItem::Trailers(Trailers::new(\n                Status::new(crate::StatusCode::Internal, \"\"),\n            )))\n            .await;\n\n        let resp = rx.next(&mut ByteRecvMsg::new()).await;\n        let ClientResponseStreamItem::Trailers(trailers) = resp else {\n            panic!(\"unexpected resp: {resp:?}\");\n        };\n        assert_eq!(trailers.status().code(), crate::StatusCode::Internal);\n    }\n\n    /// An Invoke impl that can be controlled via its paired\n    /// MockInvokerController.\n    #[derive(Clone)]\n    struct MockInvoker {\n        resp_tx: broadcast::Sender<ClientResponseStreamItem>,\n        req_tx: mpsc::Sender<(Bytes, SendOptions)>,\n    }\n    /// A controller used to control the behavior of its paired MockInvoker's\n    /// SendStream and RecvStream.\n    struct MockInvokerController {\n        resp_tx: broadcast::Sender<ClientResponseStreamItem>,\n        req_rx: mpsc::Receiver<(Bytes, SendOptions)>,\n    }\n    impl MockInvoker {\n        fn new() -> (Self, MockInvokerController) {\n            // We create receivers as needed in invoke().\n            let (resp_tx, _) = broadcast::channel(1);\n            let (req_tx, req_rx) = mpsc::channel(1);\n\n            (\n                MockInvoker {\n                    resp_tx: resp_tx.clone(),\n                    req_tx,\n                },\n                MockInvokerController { req_rx, resp_tx },\n            )\n        }\n    }\n\n    impl MockInvokerController {\n        async fn recv_req(&mut self) -> (Bytes, SendOptions) {\n            self.req_rx.recv().await.unwrap()\n        }\n        async fn send_resp(&mut self, item: ClientResponseStreamItem) {\n            self.resp_tx.send(item).unwrap();\n        }\n    }\n\n    impl Invoke for MockInvoker {\n        type SendStream = MockSendStream;\n        type RecvStream = MockRecvStream;\n\n        async fn invoke(\n            &self,\n            headers: RequestHeaders,\n            options: CallOptions,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            (\n                MockSendStream(self.req_tx.clone()),\n                MockRecvStream(self.resp_tx.subscribe()),\n            )\n        }\n    }\n\n    struct MockSendStream(mpsc::Sender<(Bytes, SendOptions)>);\n    impl SendStream for MockSendStream {\n        async fn send(&mut self, item: &dyn SendMessage, options: SendOptions) -> Result<(), ()> {\n            let mut data = item.encode().unwrap();\n            self.0\n                .send((data.copy_to_bytes(data.remaining()), options))\n                .await\n                .map_err(|_| ())\n        }\n    }\n    struct MockRecvStream(broadcast::Receiver<ClientResponseStreamItem>);\n    impl RecvStream for MockRecvStream {\n        async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n            self.0.recv().await.unwrap()\n        }\n    }\n\n    async fn start_retry_streams<I: Invoke + Clone>(\n        invoker: &I,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (RetrySendStream<I::SendStream>, RetryRecvStream<I>) {\n        let invoker = invoker.clone(); // Get an owned Invoker.\n        let (send_stream, recv_stream) = invoker.invoke(headers.clone(), options.clone()).await;\n\n        let cache = Cache::new();\n\n        (\n            RetrySendStream {\n                send_stream,\n                cache: cache.clone(),\n            },\n            RetryRecvStream {\n                invoker,\n                headers,\n                options,\n                recv_stream,\n                cache,\n                committed: false,\n            },\n        )\n    }\n\n    /// Stores information shared between a retry SendStream/RecvStream pair.\n    struct Cache<S> {\n        send_stream: Option<S>, // the most recent backing SendStream, if available\n        // Set when the stream is committed; SendStream will not wait for a new\n        // stream after a send failure when set.\n        committed: bool,\n        data: Vec<(Bytes, SendOptions)>, // cached send operations\n        // Allows the sender to wait for a new stream.\n        notify: Arc<Notify>,\n    }\n\n    impl<S> Cache<S> {\n        fn new() -> Arc<Mutex<Self>> {\n            Arc::new(Mutex::new(Cache {\n                send_stream: None,\n                committed: false,\n                data: Default::default(),\n                notify: Default::default(),\n            }))\n        }\n    }\n\n    struct RetrySendStream<S> {\n        send_stream: S, // locally cached send stream\n        cache: Arc<Mutex<Cache<S>>>,\n    }\n\n    impl<S: SendStream> SendStream for RetrySendStream<S> {\n        async fn send(&mut self, msg: &dyn SendMessage, options: SendOptions) -> Result<(), ()> {\n            loop {\n                let res = self.send_stream.send(msg, options.clone()).await;\n                let mut cache = self.cache.lock().await;\n                if cache.committed {\n                    return res;\n                }\n                if res.is_ok() {\n                    // Success; cache this message.\n                    let mut data = msg.encode().unwrap();\n                    cache\n                        .data\n                        .push((data.copy_to_bytes(data.remaining()), options));\n                    return res;\n                }\n                if cache.send_stream.is_none() {\n                    // No new stream and not committed; wait for a new stream.\n                    let notify = cache.notify.clone();\n                    drop(cache);\n                    notify.notified().await;\n                    cache = self.cache.lock().await;\n                }\n                let Some(send_stream) = cache.send_stream.take() else {\n                    // We were notified but no new stream was present; return error.\n                    return Err(());\n                };\n                // Retry on the new stream.\n                self.send_stream = send_stream;\n            }\n        }\n    }\n\n    pub struct RetryRecvStream<I: Invoke> {\n        invoker: I, // the invoker to use to retry calls\n        headers: RequestHeaders,\n        options: CallOptions,\n        recv_stream: I::RecvStream, // the most recent attempt's recv_stream\n        cache: Arc<Mutex<Cache<I::SendStream>>>,\n        // local copy of committed to avoid taking lock held by send operation\n        // if we know we have committed.\n        committed: bool,\n    }\n\n    // Returns true if we can retry a stream based on the response item -- i.e.\n    // if it is any error status.  Any other response will commit the RPC.\n    fn should_retry(i: &ClientResponseStreamItem) -> bool {\n        if let ClientResponseStreamItem::Trailers(t) = &i {\n            t.status().code() != StatusCode::Ok\n        } else {\n            false\n        }\n    }\n\n    const MAX_ATTEMPTS: usize = 3;\n\n    impl<I: Invoke> RecvStream for RetryRecvStream<I> {\n        async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n            let mut recv_resp = self.recv_stream.next(msg).await;\n\n            if self.committed {\n                return recv_resp;\n            }\n            let mut cache = self.cache.lock().await;\n            let mut attempt = 0;\n            loop {\n                attempt += 1;\n                if !should_retry(&recv_resp) || attempt > MAX_ATTEMPTS {\n                    self.committed = true;\n                    cache.committed = true;\n                    cache.data.clear();\n                    // Notify the sender in case it is blocked and waiting for a\n                    // new stream.\n                    cache.notify.notify_waiters();\n                    return recv_resp;\n                }\n\n                // Retry the whole stream.\n                let (mut send_stream, recv_stream) = self\n                    .invoker\n                    .invoke(self.headers.clone(), self.options.clone())\n                    .await;\n                self.recv_stream = recv_stream;\n\n                // Run the current recv operation in parallel with replaying\n                // the stream.\n                let recv_fut = self.recv_stream.next(msg);\n                pin!(recv_fut);\n                let mut recv_state = RecvStreamState::Pending(recv_fut);\n\n                if replay_sends(&mut send_stream, &cache.data, &mut recv_state).await {\n                    // Replay completed successfully.  Update the send stream\n                    // and release the lock while resolving the recv operation.\n                    cache.send_stream = Some(send_stream);\n                    cache.notify.notify_waiters();\n                    drop(cache);\n                    recv_resp = recv_state.resolve().await;\n                    cache = self.cache.lock().await;\n                } else {\n                    // Errors occurred while sending.  Update recv_resp and\n                    // re-check while still holding the lock.\n                    recv_resp = recv_state.resolve().await;\n                }\n            }\n        }\n    }\n\n    async fn replay_sends<S, F>(\n        send_stream: &mut S,\n        cached_sends: &Vec<(Bytes, SendOptions)>,\n        recv_state: &mut RecvStreamState<F>,\n    ) -> bool\n    where\n        S: SendStream,\n        F: Future<Output = ClientResponseStreamItem> + Unpin,\n    {\n        for (data, options) in cached_sends {\n            let send_msg = ByteSendMsg::new(data);\n            let send_fut = send_stream.send(&send_msg, options.clone());\n            pin!(send_fut);\n\n            // Poll both the recv and send until the send completes or the recv\n            // indicates we should retry.\n            loop {\n                match recv_state.race_with(&mut send_fut).await {\n                    Some(res) => {\n                        if res.is_err() {\n                            return false;\n                        }\n                        break;\n                    }\n                    None => {\n                        let RecvStreamState::Done(resp) = &recv_state else {\n                            unreachable!()\n                        };\n                        // Abort sending now if we know we need to retry.\n                        // Otherwise we will be committing, so we need to finish\n                        // replaying the sends.\n                        if should_retry(resp) {\n                            return false;\n                        }\n                    }\n                }\n            }\n        }\n        true\n    }\n\n    // Holds either a Pending() future to a recv call or its Done() result.\n    enum RecvStreamState<F> {\n        Pending(F),\n        Done(ClientResponseStreamItem),\n    }\n\n    impl<F: Future<Output = ClientResponseStreamItem> + Unpin> RecvStreamState<F> {\n        /// Runs `fut` alongside `self` if it is Pending.  Returns None if `self`\n        /// starts Pending and resolves before fut -- `self` then changes to Done\n        /// with the result.  Otherwise, returns Some(fut's output) and keeps\n        /// `self` in Pending.\n        async fn race_with<F2: Future + Unpin>(&mut self, fut: &mut F2) -> Option<F2::Output> {\n            match self {\n                RecvStreamState::Pending(recv_fut) => {\n                    select! {\n                        res = recv_fut => {\n                            *self = RecvStreamState::Done(res);\n                            None\n                        }\n                        res = fut => { Some(res) }\n                    }\n                }\n                RecvStreamState::Done(_) => Some(fut.await),\n            }\n        }\n        /// Resolves `self`: either returns the already-Done() result of the\n        /// recv operation or awaits the future and returns the result.\n        async fn resolve(self) -> ClientResponseStreamItem {\n            match self {\n                RecvStreamState::Pending(fut) => fut.await,\n                RecvStreamState::Done(resp) => resp,\n            }\n        }\n    }\n\n    struct ByteRecvMsg {\n        data: Option<Bytes>,\n    }\n    impl ByteRecvMsg {\n        fn new() -> Self {\n            Self { data: None }\n        }\n    }\n    impl RecvMessage for ByteRecvMsg {\n        fn decode(&mut self, data: &mut dyn Buf) -> Result<(), String> {\n            self.data = Some(data.copy_to_bytes(data.remaining()));\n            Ok(())\n        }\n    }\n\n    struct ByteSendMsg<'a> {\n        data: &'a Bytes,\n    }\n    impl<'a> ByteSendMsg<'a> {\n        fn new(data: &'a Bytes) -> Self {\n            Self { data }\n        }\n    }\n    impl<'a> SendMessage for ByteSendMsg<'a> {\n        fn encode(&self) -> Result<Box<dyn Buf + Send + Sync>, String> {\n            Ok(Box::new(self.data.clone()))\n        }\n    }\n\n    #[derive(Clone)]\n    struct NopInvoker;\n\n    impl Invoke for NopInvoker {\n        type SendStream = NopStream;\n        type RecvStream = NopStream;\n\n        async fn invoke(\n            &self,\n            headers: RequestHeaders,\n            options: CallOptions,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            (NopStream, NopStream)\n        }\n    }\n\n    struct NopOnceInvoker;\n\n    impl InvokeOnce for NopOnceInvoker {\n        type SendStream = NopStream;\n        type RecvStream = NopStream;\n\n        async fn invoke_once(\n            self,\n            headers: RequestHeaders,\n            options: CallOptions,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            (NopStream, NopStream)\n        }\n    }\n\n    struct NopStream;\n    impl SendStream for NopStream {\n        async fn send(&mut self, _item: &dyn SendMessage, _options: SendOptions) -> Result<(), ()> {\n            Ok(())\n        }\n    }\n    impl RecvStream for NopStream {\n        async fn next(\n            &mut self,\n            _msg: &mut dyn RecvMessage,\n        ) -> crate::core::ClientResponseStreamItem {\n            ClientResponseStreamItem::StreamClosed\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/load_balancing/child_manager.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\n//! A utility which helps parent LB policies manage multiple children for the\n//! purposes of forwarding channel updates.\n\n// TODO: This is mainly provided as a fairly complex example of the current LB\n// policy in use.  Complete tests must be written before it can be used in\n// production.\n\nuse std::collections::HashMap;\nuse std::collections::HashSet;\nuse std::error::Error;\nuse std::fmt::Debug;\nuse std::hash::Hash;\nuse std::mem;\nuse std::sync::Arc;\nuse std::sync::Mutex;\n\nuse crate::client::ConnectivityState;\nuse crate::client::load_balancing::ChannelController;\nuse crate::client::load_balancing::LbConfig;\nuse crate::client::load_balancing::LbPolicy;\nuse crate::client::load_balancing::LbPolicyBuilder;\nuse crate::client::load_balancing::LbPolicyOptions;\nuse crate::client::load_balancing::LbState;\nuse crate::client::load_balancing::Subchannel;\nuse crate::client::load_balancing::SubchannelState;\nuse crate::client::load_balancing::WeakSubchannel;\nuse crate::client::load_balancing::WorkScheduler;\nuse crate::client::name_resolution::Address;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::rt::GrpcRuntime;\n\n// An LbPolicy implementation that manages multiple children.\n#[derive(Debug)]\npub(crate) struct ChildManager<T: Debug> {\n    subchannel_to_child_idx: HashMap<WeakSubchannel, usize>,\n    children: Vec<Child<T>>,\n    pending_work: Arc<Mutex<HashSet<usize>>>,\n    runtime: GrpcRuntime,\n    updated: bool, // Set when any child updates its picker; cleared when accessed.\n    work_scheduler: Arc<dyn WorkScheduler>,\n}\n\n#[non_exhaustive]\n#[derive(Debug)]\npub(crate) struct Child<T> {\n    pub identifier: T,\n    pub builder: Arc<dyn LbPolicyBuilder>,\n    pub state: LbState,\n    policy: Box<dyn LbPolicy>,\n    work_scheduler: Arc<ChildWorkScheduler>,\n}\n\n/// A collection of data sent to a child of the ChildManager.\npub(crate) struct ChildUpdate<T> {\n    /// The identifier the ChildManager should use for this child.\n    pub child_identifier: T,\n    /// The builder the ChildManager should use to create this child if it does\n    /// not exist.  The child_policy_builder's name is effectively a part of the\n    /// child_identifier.  If two identifiers are identical but have different\n    /// builder names, they are treated as different children.\n    pub child_policy_builder: Arc<dyn LbPolicyBuilder>,\n    /// The relevant ResolverUpdate and LbConfig to send to this child.  If\n    /// None, then resolver_update will not be called on the child.  Should\n    /// generally be Some for any new children, otherwise they will not be\n    /// called.\n    pub child_update: Option<(ResolverUpdate, Option<LbConfig>)>,\n}\n\nimpl<T> ChildManager<T>\nwhere\n    T: Debug + PartialEq + Hash + Eq + Send + Sync + 'static,\n{\n    /// Creates a new ChildManager LB policy.  shard_update is called whenever a\n    /// resolver_update operation occurs.\n    pub fn new(runtime: GrpcRuntime, work_scheduler: Arc<dyn WorkScheduler>) -> Self {\n        Self {\n            subchannel_to_child_idx: Default::default(),\n            children: Default::default(),\n            pending_work: Default::default(),\n            runtime,\n            work_scheduler,\n            updated: false,\n        }\n    }\n\n    /// Returns data for all current children.\n    pub fn children(&self) -> impl Iterator<Item = &Child<T>> {\n        self.children.iter()\n    }\n\n    /// Aggregates states from child policies.\n    ///\n    /// If any child is READY then we consider the aggregate state to be READY.\n    /// Otherwise, if any child is CONNECTING, then report CONNECTING.\n    /// Otherwise, if any child is IDLE, then report IDLE.\n    /// Report TRANSIENT FAILURE if no conditions above apply.\n    pub fn aggregate_states(&self) -> ConnectivityState {\n        let mut is_connecting = false;\n        let mut is_idle = false;\n\n        for child in &self.children {\n            match child.state.connectivity_state {\n                ConnectivityState::Ready => {\n                    return ConnectivityState::Ready;\n                }\n                ConnectivityState::Connecting => {\n                    is_connecting = true;\n                }\n                ConnectivityState::Idle => {\n                    is_idle = true;\n                }\n                ConnectivityState::TransientFailure => {}\n            }\n        }\n\n        // Decide the new aggregate state if no child is READY.\n        if is_connecting {\n            ConnectivityState::Connecting\n        } else if is_idle {\n            ConnectivityState::Idle\n        } else {\n            ConnectivityState::TransientFailure\n        }\n    }\n\n    // Called to update all accounting in the ChildManager from operations\n    // performed by a child policy on the WrappedController that was created for\n    // it.  child_idx is an index into the children map for the relevant child.\n    //\n    // TODO: this post-processing step can be eliminated by capturing the right\n    // state inside the WrappedController, however it is fairly complex.  Decide\n    // which way is better.\n    fn resolve_child_controller(\n        &mut self,\n        channel_controller: WrappedController,\n        child_idx: usize,\n    ) {\n        // Add all created subchannels into the subchannel_child_map.\n        for csc in channel_controller.created_subchannels {\n            self.subchannel_to_child_idx.insert(csc.into(), child_idx);\n        }\n        // Update the tracked state if the child produced an update.\n        if let Some(state) = channel_controller.picker_update {\n            self.children[child_idx].state = state;\n            self.updated = true;\n        };\n    }\n\n    /// Returns true if any child has updated its picker since the last call to\n    /// child_updated.\n    pub fn child_updated(&mut self) -> bool {\n        mem::take(&mut self.updated)\n    }\n\n    /// Retains only the child policies specified by the iterator.\n    ///\n    /// If an ID is provided that does not exist in the ChildManager, it will be\n    /// ignored.\n    pub fn retain_children(\n        &mut self,\n        ids_builders: impl IntoIterator<Item = (T, Arc<dyn LbPolicyBuilder>)>,\n    ) {\n        self.reset_children(ids_builders, true);\n    }\n\n    /// Resets the children and all state related to tracking them in accordance\n    /// with the iterator provided.  When retain_only is true, any entry in\n    /// ids_builders that is not in the current set of children will be ignored;\n    /// otherwise a new child will be built for it.\n    fn reset_children(\n        &mut self,\n        ids_builders: impl IntoIterator<Item = (T, Arc<dyn LbPolicyBuilder>)>,\n        retain_only: bool,\n    ) {\n        // Hold the lock to prevent new work requests during this operation and\n        // rewrite the indices.\n        let mut pending_work = self.pending_work.lock().unwrap();\n\n        // Reset pending work; we will re-add any entries it contains with the\n        // right index later.\n        let old_pending_work = mem::take(&mut *pending_work);\n\n        // Replace self.children with an empty vec.\n        let old_children = mem::take(&mut self.children);\n\n        // Replace the subchannel map with an empty map.\n        let old_subchannel_child_map = mem::take(&mut self.subchannel_to_child_idx);\n\n        // Reverse the old subchannel map into a vector indexed by the old child ID.\n        let mut old_child_subchannels: Vec<Vec<WeakSubchannel>> = Vec::new();\n        old_child_subchannels.resize_with(old_children.len(), Vec::new);\n\n        for (subchannel, old_idx) in old_subchannel_child_map {\n            old_child_subchannels[old_idx].push(subchannel);\n        }\n\n        // Build a map of the old children from their IDs for efficient lookups.\n        // This leverages a Child<usize> to hold all the entries where the\n        // identifier becomes the index within the old self.children vector.\n        let mut old_children: HashMap<(&'static str, T), _> = old_children\n            .into_iter()\n            .enumerate()\n            .map(|(old_idx, e)| {\n                (\n                    (e.builder.name(), e.identifier),\n                    Child {\n                        identifier: old_idx,\n                        policy: e.policy,\n                        builder: e.builder,\n                        state: e.state,\n                        work_scheduler: e.work_scheduler,\n                    },\n                )\n            })\n            .collect();\n\n        // Transfer children whose identifiers appear before and after the\n        // update, and create new children.  Add entries back into the\n        // subchannel map.\n        for (new_idx, (identifier, builder)) in ids_builders.into_iter().enumerate() {\n            let k = (builder.name(), identifier);\n            if let Some(old_child) = old_children.remove(&k) {\n                let old_idx = old_child.identifier;\n                for subchannel in mem::take(&mut old_child_subchannels[old_idx]) {\n                    self.subchannel_to_child_idx.insert(subchannel, new_idx);\n                }\n                if old_pending_work.contains(&old_idx) {\n                    pending_work.insert(new_idx);\n                }\n                *old_child.work_scheduler.idx.lock().unwrap() = Some(new_idx);\n                self.children.push(Child {\n                    builder,\n                    identifier: k.1,\n                    state: old_child.state,\n                    policy: old_child.policy,\n                    work_scheduler: old_child.work_scheduler,\n                });\n            } else if !retain_only {\n                let work_scheduler = Arc::new(ChildWorkScheduler {\n                    pending_work: self.pending_work.clone(),\n                    idx: Mutex::new(Some(new_idx)),\n                    work_scheduler: self.work_scheduler.clone(),\n                });\n                let policy = builder.build(LbPolicyOptions {\n                    work_scheduler: work_scheduler.clone(),\n                    runtime: self.runtime.clone(),\n                });\n                self.children.push(Child {\n                    builder,\n                    identifier: k.1,\n                    state: LbState::initial(),\n                    policy,\n                    work_scheduler,\n                });\n            };\n        }\n\n        // Invalidate all deleted children's work_schedulers.\n        for (_, old_child) in old_children {\n            old_child.work_scheduler.invalidate();\n        }\n        // Anything left in old_children will just be Dropped and cleaned up.\n    }\n\n    /// Updates the ChildManager's children.\n    ///\n    /// `child_updates` is used to determine which children should exist (one\n    /// for each item), how to construct them if they don't already, and what to\n    /// send to their `resolver_update` methods, if anything.  Any existing\n    /// children not present in child_updates will be removed.\n    pub fn update(\n        &mut self,\n        child_updates: impl IntoIterator<Item = ChildUpdate<T>>,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        // Split the child updates into the IDs and builders, and the\n        // ResolverUpdates/LbConfigs.\n        let mut errs = vec![];\n        let (ids_builders, updates): (Vec<_>, Vec<_>) = child_updates\n            .into_iter()\n            .map(|e| ((e.child_identifier, e.child_policy_builder), e.child_update))\n            .unzip();\n\n        self.reset_children(ids_builders, false);\n\n        // Call resolver_update on all children.\n        let mut updates = updates.into_iter();\n        for child_idx in 0..self.children.len() {\n            let child = &mut self.children[child_idx];\n            let child_update = updates.next().unwrap();\n            let Some((resolver_update, config)) = child_update else {\n                continue;\n            };\n            let mut channel_controller = WrappedController::new(channel_controller);\n            if let Err(err) = child.policy.resolver_update(\n                resolver_update,\n                config.as_ref(),\n                &mut channel_controller,\n            ) {\n                errs.push(err);\n            }\n            self.resolve_child_controller(channel_controller, child_idx);\n        }\n        if errs.is_empty() {\n            Ok(())\n        } else {\n            let err = errs\n                .into_iter()\n                .map(|e| e.to_string())\n                .collect::<Vec<_>>()\n                .join(\"; \");\n            Err(err.into())\n        }\n    }\n\n    /// Forwards the `resolver_update` and `config` to all current children.\n    ///\n    /// Returns the Result from calling into each child.\n    pub fn resolver_update(\n        &mut self,\n        resolver_update: ResolverUpdate,\n        config: Option<&LbConfig>,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        let mut errs = Vec::with_capacity(self.children.len());\n        for child_idx in 0..self.children.len() {\n            let child = &mut self.children[child_idx];\n            let mut channel_controller = WrappedController::new(channel_controller);\n            if let Err(err) = child.policy.resolver_update(\n                resolver_update.clone(),\n                config,\n                &mut channel_controller,\n            ) {\n                errs.push(err);\n            }\n            self.resolve_child_controller(channel_controller, child_idx);\n        }\n        if errs.is_empty() {\n            Ok(())\n        } else {\n            let err = errs\n                .into_iter()\n                .map(|e| e.to_string())\n                .collect::<Vec<_>>()\n                .join(\"; \");\n            Err(err.into())\n        }\n    }\n\n    /// Forwards the incoming subchannel_update to the child that created the\n    /// subchannel being updated.\n    pub fn subchannel_update(\n        &mut self,\n        subchannel: Arc<dyn Subchannel>,\n        state: &SubchannelState,\n        channel_controller: &mut dyn ChannelController,\n    ) {\n        // Determine which child created this subchannel.\n        let child_idx = *self\n            .subchannel_to_child_idx\n            .get(&WeakSubchannel::new(&subchannel))\n            .unwrap();\n        let policy = &mut self.children[child_idx].policy;\n        // Wrap the channel_controller to track the child's operations.\n        let mut channel_controller = WrappedController::new(channel_controller);\n        // Call the proper child.\n        policy.subchannel_update(subchannel, state, &mut channel_controller);\n        self.resolve_child_controller(channel_controller, child_idx);\n    }\n\n    /// Calls work on any children that scheduled work via the work scheduler.\n    pub fn work(&mut self, channel_controller: &mut dyn ChannelController) {\n        let child_idxes = mem::take(&mut *self.pending_work.lock().unwrap());\n        for child_idx in child_idxes {\n            let mut channel_controller = WrappedController::new(channel_controller);\n            self.children[child_idx]\n                .policy\n                .work(&mut channel_controller);\n            self.resolve_child_controller(channel_controller, child_idx);\n        }\n    }\n\n    /// Calls exit_idle on all children.\n    pub fn exit_idle(&mut self, channel_controller: &mut dyn ChannelController) {\n        for child_idx in 0..self.children.len() {\n            let child = &mut self.children[child_idx];\n            let mut channel_controller = WrappedController::new(channel_controller);\n            child.policy.exit_idle(&mut channel_controller);\n            self.resolve_child_controller(channel_controller, child_idx);\n        }\n    }\n}\n\nstruct WrappedController<'a> {\n    channel_controller: &'a mut dyn ChannelController,\n    created_subchannels: Vec<Arc<dyn Subchannel>>,\n    picker_update: Option<LbState>,\n}\n\nimpl<'a> WrappedController<'a> {\n    fn new(channel_controller: &'a mut dyn ChannelController) -> Self {\n        Self {\n            channel_controller,\n            created_subchannels: vec![],\n            picker_update: None,\n        }\n    }\n}\n\nimpl ChannelController for WrappedController<'_> {\n    fn new_subchannel(&mut self, address: &Address) -> Arc<dyn Subchannel> {\n        let subchannel = self.channel_controller.new_subchannel(address);\n        self.created_subchannels.push(subchannel.clone());\n        subchannel\n    }\n\n    fn update_picker(&mut self, update: LbState) {\n        self.picker_update = Some(update);\n    }\n\n    fn request_resolution(&mut self) {\n        self.channel_controller.request_resolution();\n    }\n}\n\n#[derive(Debug)]\nstruct ChildWorkScheduler {\n    work_scheduler: Arc<dyn WorkScheduler>, // The real work scheduler of the channel.\n    pending_work: Arc<Mutex<HashSet<usize>>>, // Must be taken first for correctness\n    idx: Mutex<Option<usize>>,              // None if the child is deleted.\n}\n\nimpl WorkScheduler for ChildWorkScheduler {\n    fn schedule_work(&self) {\n        let mut pending_work = self.pending_work.lock().unwrap();\n        // If self.idx is None then this WorkScheduler has been invalidated as\n        // it is associated with a deleted child; do nothing in that case.\n        if let Some(idx) = *self.idx.lock().unwrap() {\n            pending_work.insert(idx);\n            self.work_scheduler.schedule_work();\n        }\n    }\n}\n\nimpl ChildWorkScheduler {\n    // Sets the ChildWorkScheduler so that it will not honor future\n    // schedule_work requests.\n    fn invalidate(&self) {\n        *self.idx.lock().unwrap() = None;\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use crate::client::ConnectivityState;\n    use crate::client::load_balancing::ChannelController;\n    use crate::client::load_balancing::GLOBAL_LB_REGISTRY;\n    use crate::client::load_balancing::LbPolicyBuilder;\n    use crate::client::load_balancing::LbState;\n    use crate::client::load_balancing::QueuingPicker;\n    use crate::client::load_balancing::Subchannel;\n    use crate::client::load_balancing::SubchannelState;\n    use crate::client::load_balancing::child_manager::ChildManager;\n    use crate::client::load_balancing::child_manager::ChildUpdate;\n    use crate::client::load_balancing::test_utils::StubPolicyFuncs;\n    use crate::client::load_balancing::test_utils::TestChannelController;\n    use crate::client::load_balancing::test_utils::TestEvent;\n    use crate::client::load_balancing::test_utils::TestWorkScheduler;\n    use crate::client::load_balancing::test_utils::{self};\n    use crate::client::name_resolution::Address;\n    use crate::client::name_resolution::Endpoint;\n    use crate::client::name_resolution::ResolverUpdate;\n    use crate::client::service_config::LbConfig;\n    use crate::rt::default_runtime;\n    use std::collections::HashMap;\n    use std::error::Error;\n    use std::panic;\n    use std::sync::Arc;\n    use std::sync::Mutex;\n    use tokio::sync::mpsc;\n\n    // Sets up the test environment.\n    //\n    // Performs the following:\n    // 1. Creates a work scheduler.\n    // 2. Creates a fake channel that acts as a channel controller.\n    // 3. Creates an StubPolicyBuilder with StubFuncs that each test will define\n    //    and name of the test.\n    // 4. Creates an EndpointSharder with StubPolicyBuilder passed in as the\n    //    child policy.\n    // 5. Creates a ChildManager with the EndpointSharder.\n    //\n    // Returns the following:\n    // 1. A receiver for events initiated by the LB policy (like creating a new\n    //    subchannel, sending a new picker etc).\n    // 2. The ChildManager to send resolver and subchannel updates from the\n    //    test.\n    // 3. The controller to pass to the LB policy as part of the updates.\n    fn setup(\n        funcs: StubPolicyFuncs,\n        test_name: &'static str,\n    ) -> (\n        mpsc::UnboundedReceiver<TestEvent>,\n        ChildManager<Endpoint>,\n        Box<dyn ChannelController>,\n    ) {\n        test_utils::reg_stub_policy(test_name, funcs);\n        let (tx_events, rx_events) = mpsc::unbounded_channel::<TestEvent>();\n        let tcc = Box::new(TestChannelController {\n            tx_events: tx_events.clone(),\n        });\n        let child_manager =\n            ChildManager::new(default_runtime(), Arc::new(TestWorkScheduler { tx_events }));\n        (rx_events, child_manager, tcc)\n    }\n\n    fn create_n_endpoints_with_k_addresses(n: usize, k: usize) -> Vec<Endpoint> {\n        let mut endpoints = Vec::with_capacity(n);\n        for i in 0..n {\n            let mut addresses: Vec<Address> = Vec::with_capacity(k);\n            for j in 0..k {\n                addresses.push(Address {\n                    address: format!(\"{}.{}.{}.{}:{}\", i + 1, i + 1, i + 1, i + 1, j).into(),\n                    ..Default::default()\n                });\n            }\n            endpoints.push(Endpoint {\n                addresses,\n                ..Default::default()\n            })\n        }\n        endpoints\n    }\n\n    // Sends a resolver update to the LB policy with the specified endpoint.\n    fn send_resolver_update_to_policy(\n        child_manager: &mut ChildManager<Endpoint>,\n        endpoints: Vec<Endpoint>,\n        builder: Arc<dyn LbPolicyBuilder>,\n        tcc: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        let updates = endpoints.iter().map(|e| ChildUpdate {\n            child_identifier: e.clone(),\n            child_policy_builder: builder.clone(),\n            child_update: Some((\n                ResolverUpdate {\n                    attributes: crate::attributes::Attributes::default(),\n                    endpoints: Ok(vec![e.clone()]),\n                    service_config: Ok(None),\n                    resolution_note: None,\n                },\n                None,\n            )),\n        });\n\n        child_manager.update(updates, tcc)\n    }\n\n    fn move_subchannel_to_state(\n        child_manager: &mut ChildManager<Endpoint>,\n        subchannel: Arc<dyn Subchannel>,\n        tcc: &mut dyn ChannelController,\n        state: ConnectivityState,\n    ) {\n        child_manager.subchannel_update(\n            subchannel,\n            &SubchannelState {\n                connectivity_state: state,\n                ..Default::default()\n            },\n            tcc,\n        );\n    }\n\n    // Verifies that the expected number of subchannels is created. Returns the\n    // subchannels created.\n    async fn verify_subchannel_creation_from_policy(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n        number_of_subchannels: usize,\n    ) -> Vec<Arc<dyn Subchannel>> {\n        let mut subchannels = Vec::new();\n        for _ in 0..number_of_subchannels {\n            match rx_events.recv().await.unwrap() {\n                TestEvent::NewSubchannel(sc) => {\n                    subchannels.push(sc);\n                }\n                other => panic!(\"unexpected event {:?}\", other),\n            };\n        }\n        subchannels\n    }\n\n    // Defines the functions resolver_update and subchannel_update to test\n    // aggregate_states.\n    fn create_verifying_funcs_for_aggregate_tests() -> StubPolicyFuncs {\n        StubPolicyFuncs {\n            // Closure for resolver_update. resolver_update should only receive\n            // one endpoint and create one subchannel for the endpoint it\n            // receives.\n            resolver_update: Some(Arc::new(\n                move |data, update: ResolverUpdate, _, controller| {\n                    assert_eq!(update.endpoints.iter().len(), 1);\n                    let endpoint = update.endpoints.unwrap().pop().unwrap();\n                    let subchannel = controller.new_subchannel(&endpoint.addresses[0]);\n                    Ok(())\n                },\n            )),\n            // Closure for subchannel_update. Sends a picker of the same state\n            // that was passed to it.\n            subchannel_update: Some(Arc::new(\n                move |data, updated_subchannel, state, controller| {\n                    controller.update_picker(LbState {\n                        connectivity_state: state.connectivity_state,\n                        picker: Arc::new(QueuingPicker {}),\n                    });\n                },\n            )),\n            work: None,\n        }\n    }\n\n    // Tests the scenario where one child is READY and the rest are in\n    // CONNECTING, IDLE, or TRANSIENT FAILURE. The child manager's\n    // aggregate_states function should report READY.\n    #[tokio::test]\n    async fn childmanager_aggregate_state_is_ready_if_any_child_is_ready() {\n        let test_name = \"stub-childmanager_aggregate_state_is_ready_if_any_child_is_ready\";\n        let (mut rx_events, mut child_manager, mut tcc) =\n            setup(create_verifying_funcs_for_aggregate_tests(), test_name);\n        let builder: Arc<dyn LbPolicyBuilder> = GLOBAL_LB_REGISTRY.get_policy(test_name).unwrap();\n\n        let endpoints = create_n_endpoints_with_k_addresses(4, 1);\n        send_resolver_update_to_policy(\n            &mut child_manager,\n            endpoints.clone(),\n            builder,\n            tcc.as_mut(),\n        )\n        .unwrap();\n        let mut subchannels = vec![];\n        for endpoint in endpoints {\n            subchannels.push(\n                verify_subchannel_creation_from_policy(&mut rx_events, endpoint.addresses.len())\n                    .await\n                    .remove(0),\n            );\n        }\n\n        let mut subchannels = subchannels.into_iter();\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::TransientFailure,\n        );\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::Idle,\n        );\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::Connecting,\n        );\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        assert_eq!(child_manager.aggregate_states(), ConnectivityState::Ready);\n    }\n\n    // Tests the scenario where no children are READY and the children are in\n    // CONNECTING, IDLE, or TRANSIENT FAILURE. The child manager's\n    // aggregate_states function should report CONNECTING.\n    #[tokio::test]\n    async fn childmanager_aggregate_state_is_connecting_if_no_child_is_ready() {\n        let test_name = \"stub-childmanager_aggregate_state_is_connecting_if_no_child_is_ready\";\n        let (mut rx_events, mut child_manager, mut tcc) =\n            setup(create_verifying_funcs_for_aggregate_tests(), test_name);\n        let builder: Arc<dyn LbPolicyBuilder> = GLOBAL_LB_REGISTRY.get_policy(test_name).unwrap();\n        let endpoints = create_n_endpoints_with_k_addresses(3, 1);\n        send_resolver_update_to_policy(\n            &mut child_manager,\n            endpoints.clone(),\n            builder,\n            tcc.as_mut(),\n        )\n        .unwrap();\n        let mut subchannels = vec![];\n        for endpoint in endpoints {\n            subchannels.push(\n                verify_subchannel_creation_from_policy(&mut rx_events, endpoint.addresses.len())\n                    .await\n                    .remove(0),\n            );\n        }\n        let mut subchannels = subchannels.into_iter();\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::TransientFailure,\n        );\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::Idle,\n        );\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::Connecting,\n        );\n\n        assert_eq!(\n            child_manager.aggregate_states(),\n            ConnectivityState::Connecting\n        );\n    }\n\n    // Tests the scenario where no children are READY or CONNECTING and the\n    // children are in IDLE, or TRANSIENT FAILURE. The child manager's\n    // aggregate_states function should report IDLE.\n    #[tokio::test]\n    async fn childmanager_aggregate_state_is_idle_if_only_idle_and_failure() {\n        let test_name = \"stub-childmanager_aggregate_state_is_idle_if_only_idle_and_failure\";\n        let (mut rx_events, mut child_manager, mut tcc) =\n            setup(create_verifying_funcs_for_aggregate_tests(), test_name);\n        let builder: Arc<dyn LbPolicyBuilder> = GLOBAL_LB_REGISTRY.get_policy(test_name).unwrap();\n\n        let endpoints = create_n_endpoints_with_k_addresses(2, 1);\n        send_resolver_update_to_policy(\n            &mut child_manager,\n            endpoints.clone(),\n            builder,\n            tcc.as_mut(),\n        )\n        .unwrap();\n        let mut subchannels = vec![];\n        for endpoint in endpoints {\n            subchannels.push(\n                verify_subchannel_creation_from_policy(&mut rx_events, endpoint.addresses.len())\n                    .await\n                    .remove(0),\n            );\n        }\n        let mut subchannels = subchannels.into_iter();\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::TransientFailure,\n        );\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::Idle,\n        );\n        assert_eq!(child_manager.aggregate_states(), ConnectivityState::Idle);\n    }\n\n    // Tests the scenario where no children are READY, CONNECTING, or IDLE and\n    // all children are in TRANSIENT FAILURE. The child manager's\n    // aggregate_states function should report TRANSIENT FAILURE.\n    #[tokio::test]\n    async fn childmanager_aggregate_state_is_transient_failure_if_all_children_are() {\n        let test_name =\n            \"stub-childmanager_aggregate_state_is_transient_failure_if_all_children_are\";\n        let (mut rx_events, mut child_manager, mut tcc) =\n            setup(create_verifying_funcs_for_aggregate_tests(), test_name);\n        let builder: Arc<dyn LbPolicyBuilder> = GLOBAL_LB_REGISTRY.get_policy(test_name).unwrap();\n        let endpoints = create_n_endpoints_with_k_addresses(2, 1);\n        send_resolver_update_to_policy(\n            &mut child_manager,\n            endpoints.clone(),\n            builder,\n            tcc.as_mut(),\n        )\n        .unwrap();\n        let mut subchannels = vec![];\n        for endpoint in endpoints {\n            subchannels.push(\n                verify_subchannel_creation_from_policy(&mut rx_events, endpoint.addresses.len())\n                    .await\n                    .remove(0),\n            );\n        }\n        let mut subchannels = subchannels.into_iter();\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::TransientFailure,\n        );\n        move_subchannel_to_state(\n            &mut child_manager,\n            subchannels.next().unwrap(),\n            tcc.as_mut(),\n            ConnectivityState::TransientFailure,\n        );\n        assert_eq!(\n            child_manager.aggregate_states(),\n            ConnectivityState::TransientFailure\n        );\n    }\n\n    struct ScheduleWorkStubData {\n        requested_work: bool,\n    }\n\n    fn create_funcs_for_schedule_work_tests(name: &'static str) -> StubPolicyFuncs {\n        StubPolicyFuncs {\n            resolver_update: Some(Arc::new(move |data, _update, lbcfg, _controller| {\n                if data.test_data.is_none() {\n                    data.test_data = Some(Box::new(ScheduleWorkStubData {\n                        requested_work: false,\n                    }));\n                }\n                let stubdata = data\n                    .test_data\n                    .as_mut()\n                    .unwrap()\n                    .downcast_mut::<ScheduleWorkStubData>()\n                    .unwrap();\n                assert!(!stubdata.requested_work);\n                if lbcfg\n                    .unwrap()\n                    .convert_to::<Mutex<HashMap<&'static str, ()>>>()\n                    .unwrap()\n                    .lock()\n                    .unwrap()\n                    .contains_key(name)\n                {\n                    stubdata.requested_work = true;\n                    data.lb_policy_options.work_scheduler.schedule_work();\n                }\n                Ok(())\n            })),\n            subchannel_update: None,\n            work: Some(Arc::new(move |data, _controller| {\n                println!(\"work called for {name}\");\n                let stubdata = data\n                    .test_data\n                    .as_mut()\n                    .unwrap()\n                    .downcast_mut::<ScheduleWorkStubData>()\n                    .unwrap();\n                stubdata.requested_work = false;\n            })),\n        }\n    }\n\n    // Tests that the child manager properly delegates to the children that\n    // called schedule_work when work is called.\n    #[tokio::test]\n    async fn childmanager_schedule_work_works() {\n        let name1 = \"childmanager_schedule_work_works-one\";\n        let name2 = \"childmanager_schedule_work_works-two\";\n        test_utils::reg_stub_policy(name1, create_funcs_for_schedule_work_tests(name1));\n        test_utils::reg_stub_policy(name2, create_funcs_for_schedule_work_tests(name2));\n\n        let (tx_events, mut rx_events) = mpsc::unbounded_channel::<TestEvent>();\n        let mut tcc = TestChannelController {\n            tx_events: tx_events.clone(),\n        };\n\n        let names = [name1, name2];\n        let mut child_manager =\n            ChildManager::new(default_runtime(), Arc::new(TestWorkScheduler { tx_events }));\n\n        // Request that child one requests work.\n        let cfg = LbConfig::new(Mutex::new(HashMap::<&'static str, ()>::new()));\n        let children = cfg\n            .convert_to::<Mutex<HashMap<&'static str, ()>>>()\n            .unwrap();\n        children.lock().unwrap().insert(name1, ());\n\n        let updates = names.iter().map(|name| {\n            let child_policy_builder: Arc<dyn LbPolicyBuilder> =\n                GLOBAL_LB_REGISTRY.get_policy(name).unwrap();\n\n            ChildUpdate {\n                child_identifier: (),\n                child_policy_builder,\n                child_update: Some((ResolverUpdate::default(), Some(cfg.clone()))),\n            }\n        });\n        child_manager.update(updates.clone(), &mut tcc).unwrap();\n\n        // Confirm that child one has requested work.\n        match rx_events.recv().await.unwrap() {\n            TestEvent::ScheduleWork => {}\n            other => panic!(\"unexpected event {:?}\", other),\n        };\n        assert_eq!(child_manager.pending_work.lock().unwrap().len(), 1);\n        let idx = *child_manager\n            .pending_work\n            .lock()\n            .unwrap()\n            .iter()\n            .next()\n            .unwrap();\n        assert_eq!(child_manager.children[idx].builder.name(), name1);\n\n        // Perform the work call and assert the pending_work set is empty.\n        child_manager.work(&mut tcc);\n        assert_eq!(child_manager.pending_work.lock().unwrap().len(), 0);\n\n        // Now have both children request work.\n        children.lock().unwrap().insert(name2, ());\n\n        child_manager.update(updates.clone(), &mut tcc).unwrap();\n\n        // Confirm that both children requested work.\n        match rx_events.recv().await.unwrap() {\n            TestEvent::ScheduleWork => {}\n            other => panic!(\"unexpected event {:?}\", other),\n        };\n        assert_eq!(child_manager.pending_work.lock().unwrap().len(), 2);\n\n        // Perform the work call and assert the pending_work set is empty.\n        child_manager.work(&mut tcc);\n        assert_eq!(child_manager.pending_work.lock().unwrap().len(), 0);\n\n        // Perform one final call to resolver_update which asserts that both\n        // child policies had their work methods called.\n        child_manager.update(updates, &mut tcc).unwrap();\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/load_balancing/graceful_switch.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::collections::HashMap;\nuse std::error::Error;\nuse std::sync::Arc;\n\nuse crate::client::ConnectivityState;\nuse crate::client::load_balancing::ChannelController;\nuse crate::client::load_balancing::GLOBAL_LB_REGISTRY;\nuse crate::client::load_balancing::LbConfig;\nuse crate::client::load_balancing::LbPolicy;\nuse crate::client::load_balancing::LbPolicyBuilder;\nuse crate::client::load_balancing::LbState;\nuse crate::client::load_balancing::ParsedJsonLbConfig;\nuse crate::client::load_balancing::Subchannel;\nuse crate::client::load_balancing::SubchannelState;\nuse crate::client::load_balancing::WorkScheduler;\nuse crate::client::load_balancing::child_manager::ChildManager;\nuse crate::client::load_balancing::child_manager::ChildUpdate;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::rt::GrpcRuntime;\n\n#[derive(Debug, Clone)]\nstruct GracefulSwitchLbConfig {\n    child_builder: Arc<dyn LbPolicyBuilder>,\n    child_config: Option<LbConfig>,\n}\n\n/// A graceful switching load balancing policy.  In graceful switch, there is\n/// always either one or two child policies.  When there is one policy, all\n/// operations are delegated to it.  When the child policy type needs to change,\n/// graceful switch creates a \"pending\" child policy alongside the \"active\"\n/// policy.  When the pending policy leaves the CONNECTING state, or when the\n/// active policy is not READY, graceful switch will promote the pending policy\n/// to to active and tear down the previously active policy.\n#[derive(Debug)]\npub(crate) struct GracefulSwitchPolicy {\n    child_manager: ChildManager<()>, // Child ID empty - only the name of the child LB policy matters.\n    last_update: Option<LbState>, // Saves the last output LbState to determine if an update is needed.\n    active_child_builder: Option<Arc<dyn LbPolicyBuilder>>,\n}\n\nimpl LbPolicy for GracefulSwitchPolicy {\n    fn resolver_update(\n        &mut self,\n        update: ResolverUpdate,\n        config: Option<&LbConfig>,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        let config = config\n            .ok_or(\"graceful switch received no config\")?\n            .convert_to::<GracefulSwitchLbConfig>()\n            .ok_or_else(|| format!(\"invalid config: {config:?}\"))?;\n\n        if self.active_child_builder.is_none() {\n            // When there are no children yet, the current update immediately\n            // becomes the active child.\n            self.active_child_builder = Some(config.child_builder.clone());\n        }\n        let active_child_builder = self.active_child_builder.as_ref().unwrap();\n\n        let mut children = Vec::with_capacity(2);\n\n        // Always include the incoming update.\n        children.push(ChildUpdate {\n            child_policy_builder: config.child_builder.clone(),\n            child_identifier: (),\n            child_update: Some((update, config.child_config.clone())),\n        });\n\n        // Include the active child if it does not match the updated child so\n        // that the child manager will not delete it.\n        if config.child_builder.name() != active_child_builder.name() {\n            children.push(ChildUpdate {\n                child_policy_builder: active_child_builder.clone(),\n                child_identifier: (),\n                child_update: None,\n            });\n        }\n\n        let res = self.child_manager.update(children, channel_controller);\n        self.update_picker(channel_controller);\n        res\n    }\n\n    fn subchannel_update(\n        &mut self,\n        subchannel: Arc<dyn Subchannel>,\n        state: &SubchannelState,\n        channel_controller: &mut dyn ChannelController,\n    ) {\n        self.child_manager\n            .subchannel_update(subchannel, state, channel_controller);\n        self.update_picker(channel_controller);\n    }\n\n    fn work(&mut self, channel_controller: &mut dyn ChannelController) {\n        self.child_manager.work(channel_controller);\n        self.update_picker(channel_controller);\n    }\n\n    fn exit_idle(&mut self, channel_controller: &mut dyn ChannelController) {\n        self.child_manager.exit_idle(channel_controller);\n        self.update_picker(channel_controller);\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\nenum ChildKind {\n    Current,\n    Pending,\n}\n\nimpl GracefulSwitchPolicy {\n    /// Creates a new Graceful Switch policy.\n    pub fn new(runtime: GrpcRuntime, work_scheduler: Arc<dyn WorkScheduler>) -> Self {\n        GracefulSwitchPolicy {\n            child_manager: ChildManager::new(runtime, work_scheduler),\n            last_update: None,\n            active_child_builder: None,\n        }\n    }\n\n    /// Parses a child config list and returns a LB config for the\n    /// GracefulSwitchPolicy.  Config is expected to contain a JSON array of LB\n    /// policy names + configs matching the format of the \"loadBalancingConfig\"\n    /// field in the gRPC ServiceConfig. It returns a type that should be passed\n    /// to resolver_update in the LbConfig.config field.\n    pub fn parse_config(\n        config: &ParsedJsonLbConfig,\n    ) -> Result<LbConfig, Box<dyn Error + Send + Sync>> {\n        let cfg: Vec<HashMap<String, serde_json::Value>> = match config.convert_to() {\n            Ok(c) => c,\n            Err(e) => {\n                return Err(format!(\"failed to parse JSON config: {}\", e).into());\n            }\n        };\n        for c in cfg {\n            if c.len() != 1 {\n                return Err(format!(\n                    \"Each element in array must contain exactly one policy name/config; found {:?}\",\n                    c.keys()\n                )\n                .into());\n            }\n            let (policy_name, policy_config) = c.into_iter().next().unwrap();\n            let Some(child_builder) = GLOBAL_LB_REGISTRY.get_policy(policy_name.as_str()) else {\n                continue;\n            };\n            let parsed_config = ParsedJsonLbConfig {\n                value: policy_config,\n            };\n            let child_config = child_builder.parse_config(&parsed_config)?;\n            let gsb_config = GracefulSwitchLbConfig {\n                child_builder,\n                child_config,\n            };\n            return Ok(LbConfig::new(gsb_config));\n        }\n        Err(\"no supported policies found in config\".into())\n    }\n\n    fn update_picker(&mut self, channel_controller: &mut dyn ChannelController) {\n        // If maybe_swap returns a None, then no update needs to happen.\n        let Some(update) = self.maybe_swap(channel_controller) else {\n            return;\n        };\n        // If the current update is the same as the last update, skip it.\n        if self.last_update.as_ref().is_some_and(|lu| lu == &update) {\n            return;\n        }\n        channel_controller.update_picker(update.clone());\n        self.last_update = Some(update);\n    }\n\n    // Determines the appropriate state to output\n    fn maybe_swap(&mut self, channel_controller: &mut dyn ChannelController) -> Option<LbState> {\n        // If no child updated itself, there is nothing we can do.\n        if !self.child_manager.child_updated() {\n            return None;\n        }\n\n        // If resolver_update has never been called, we have no children, so\n        // there's nothing we can do.\n        let Some(active_child_builder) = &self.active_child_builder else {\n            return None;\n        };\n        let active_name = active_child_builder.name();\n\n        // Scan through the child manager's children for the active and\n        // (optional) pending child.\n        let mut active_child = None;\n        let mut pending_child = None;\n        for child in self.child_manager.children() {\n            if child.builder.name() == active_name {\n                active_child = Some(child);\n            } else {\n                pending_child = Some(child);\n            }\n        }\n        let active_child = active_child.expect(\"There should always be an active child policy\");\n\n        // If no pending child exists, we will update the active child's state.\n        let Some(pending_child) = pending_child else {\n            return Some(active_child.state.clone());\n        };\n\n        // If the active child is still reading and the pending child is still\n        // connecting, keep using the active child's state.\n        if active_child.state.connectivity_state == ConnectivityState::Ready\n            && pending_child.state.connectivity_state == ConnectivityState::Connecting\n        {\n            return Some(active_child.state.clone());\n        }\n\n        // Transition to the pending child and remove the active child.\n\n        // Clone some things from child_manager.children to release the\n        // child_manager reference.\n        let pending_child_builder = pending_child.builder.clone();\n        let pending_state = pending_child.state.clone();\n\n        self.active_child_builder = Some(pending_child_builder.clone());\n        self.child_manager\n            .retain_children([((), pending_child_builder)]);\n\n        Some(pending_state)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use crate::client::ConnectivityState;\n    use crate::client::load_balancing::ChannelController;\n    use crate::client::load_balancing::LbPolicy;\n    use crate::client::load_balancing::LbState;\n    use crate::client::load_balancing::ParsedJsonLbConfig;\n    use crate::client::load_balancing::Pick;\n    use crate::client::load_balancing::PickResult;\n    use crate::client::load_balancing::Picker;\n    use crate::client::load_balancing::Subchannel;\n    use crate::client::load_balancing::SubchannelState;\n    use crate::client::load_balancing::graceful_switch::GracefulSwitchPolicy;\n    use crate::client::load_balancing::test_utils::StubPolicyData;\n    use crate::client::load_balancing::test_utils::StubPolicyFuncs;\n    use crate::client::load_balancing::test_utils::TestChannelController;\n    use crate::client::load_balancing::test_utils::TestEvent;\n    use crate::client::load_balancing::test_utils::TestSubchannel;\n    use crate::client::load_balancing::test_utils::TestWorkScheduler;\n    use crate::client::load_balancing::test_utils::reg_stub_policy;\n    use crate::client::load_balancing::test_utils::{self};\n    use crate::client::name_resolution::Address;\n    use crate::client::name_resolution::Endpoint;\n    use crate::client::name_resolution::ResolverUpdate;\n    use crate::core::RequestHeaders;\n    use crate::rt::default_runtime;\n    use std::panic;\n    use std::sync::Arc;\n    use std::time::Duration;\n    use tokio::select;\n    use tokio::sync::mpsc::UnboundedReceiver;\n    use tokio::sync::mpsc::{self};\n    use tonic::metadata::MetadataMap;\n\n    const DEFAULT_TEST_SHORT_TIMEOUT: Duration = Duration::from_millis(10);\n\n    struct TestSubchannelList {\n        subchannels: Vec<Arc<dyn Subchannel>>,\n    }\n\n    impl TestSubchannelList {\n        fn new(addresses: &Vec<Address>, channel_controller: &mut dyn ChannelController) -> Self {\n            let mut scl = TestSubchannelList {\n                subchannels: Vec::new(),\n            };\n            for address in addresses {\n                let sc = channel_controller.new_subchannel(address);\n                scl.subchannels.push(sc.clone());\n            }\n            scl\n        }\n\n        fn contains(&self, sc: &Arc<dyn Subchannel>) -> bool {\n            self.subchannels.contains(sc)\n        }\n    }\n\n    #[derive(Debug)]\n    struct TestPicker {\n        name: &'static str,\n    }\n\n    impl TestPicker {\n        fn new(name: &'static str) -> Self {\n            Self { name }\n        }\n    }\n    impl Picker for TestPicker {\n        fn pick(&self, _req: &RequestHeaders) -> PickResult {\n            PickResult::Pick(Pick {\n                subchannel: Arc::new(TestSubchannel::new(\n                    Address {\n                        address: self.name.to_string().into(),\n                        ..Default::default()\n                    },\n                    mpsc::unbounded_channel().0,\n                )),\n                metadata: MetadataMap::new(),\n                on_complete: None,\n            })\n        }\n    }\n\n    struct TestState {\n        subchannel_list: TestSubchannelList,\n    }\n\n    // Defines the functions resolver_update and subchannel_update to test graceful switch\n    fn create_funcs_for_gracefulswitch_tests(name: &'static str) -> StubPolicyFuncs {\n        StubPolicyFuncs {\n            // Closure for resolver_update. It creates a subchannel for the\n            // endpoint it receives and stores which endpoint it received and\n            // which subchannel this child created in the data field.\n            resolver_update: Some(Arc::new(\n                move |data: &mut StubPolicyData, update: ResolverUpdate, _, channel_controller| {\n                    if let Ok(ref endpoints) = update.endpoints {\n                        let addresses: Vec<_> = endpoints\n                            .iter()\n                            .flat_map(|ep| ep.addresses.clone())\n                            .collect();\n                        let scl = TestSubchannelList::new(&addresses, channel_controller);\n                        let child_state = TestState {\n                            subchannel_list: scl,\n                        };\n                        data.test_data = Some(Box::new(child_state));\n                    } else {\n                        data.test_data = None;\n                    }\n                    Ok(())\n                },\n            )),\n            // Closure for subchannel_update. Verify that the subchannel that\n            // being updated now is the same one that this child policy created\n            // in resolver_update. It then sends a picker of the same state that\n            // was passed to it.\n            subchannel_update: Some(Arc::new(\n                move |data: &mut StubPolicyData, updated_subchannel, state, channel_controller| {\n                    // Retrieve the specific TestState from the generic test_data field.\n                    // This downcasts the `Any` trait object.\n                    let test_data = data.test_data.as_mut().unwrap();\n                    let test_state = test_data.downcast_mut::<TestState>().unwrap();\n                    let scl = &mut test_state.subchannel_list;\n                    assert!(\n                        scl.contains(&updated_subchannel),\n                        \"subchannel_update received an update for a subchannel it does not own.\"\n                    );\n                    channel_controller.update_picker(LbState {\n                        connectivity_state: state.connectivity_state,\n                        picker: Arc::new(TestPicker { name }),\n                    });\n                },\n            )),\n            work: None,\n        }\n    }\n\n    // Sets up the test environment.\n    //\n    // Performs the following:\n    // 1. Creates a work scheduler.\n    // 2. Creates a fake channel that acts as a channel controller.\n    // 3. Creates an StubPolicyBuilder with StubFuncs that each test will define\n    //    and name of the test.\n    // 5. Creates a GracefulSwitch.\n    //\n    // Returns the following:\n    // 1. A receiver for events initiated by the LB policy (like creating a new\n    //    subchannel, sending a new picker etc).\n    // 2. The GracefulSwitch to send resolver and subchannel updates from the\n    //    test.\n    // 3. The controller to pass to the LB policy as part of the updates.\n    fn setup() -> (\n        mpsc::UnboundedReceiver<TestEvent>,\n        Box<GracefulSwitchPolicy>,\n        Box<dyn ChannelController>,\n    ) {\n        let (tx_events, rx_events) = mpsc::unbounded_channel::<TestEvent>();\n        let work_scheduler = Arc::new(TestWorkScheduler {\n            tx_events: tx_events.clone(),\n        });\n\n        let tcc = Box::new(TestChannelController {\n            tx_events: tx_events.clone(),\n        });\n\n        let graceful_switch =\n            GracefulSwitchPolicy::new(default_runtime(), Arc::new(TestWorkScheduler { tx_events }));\n        (rx_events, Box::new(graceful_switch), tcc)\n    }\n\n    fn create_endpoint_with_one_address(addr: String) -> Endpoint {\n        Endpoint {\n            addresses: vec![Address {\n                address: addr.into(),\n                ..Default::default()\n            }],\n            ..Default::default()\n        }\n    }\n\n    // Verifies that the next event on rx_events channel is NewSubchannel.\n    // Returns the subchannel created.\n    async fn verify_subchannel_creation_from_policy(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n    ) -> Arc<dyn Subchannel> {\n        match rx_events.recv().await.unwrap() {\n            TestEvent::NewSubchannel(sc) => sc,\n            other => panic!(\"unexpected event {:?}\", other),\n        }\n    }\n\n    // Verifies that the channel moves to READY state with a picker that returns the\n    // given subchannel.\n    //\n    // Returns the picker for tests to make more picks, if required.\n    async fn verify_correct_picker_from_policy(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n        name: &str,\n    ) {\n        println!(\"verify ready picker\");\n        let event = rx_events.recv().await.unwrap();\n        let TestEvent::UpdatePicker(update) = event else {\n            panic!(\"unexpected event {:?}\", event);\n        };\n        let req = test_utils::new_request_headers();\n        println!(\"{:?}\", update.connectivity_state);\n\n        let pick = update.picker.pick(&req);\n        let PickResult::Pick(pick) = pick else {\n            panic!(\"unexpected pick result: {:?}\", pick);\n        };\n        let received_address = &pick.subchannel.address().address.to_string();\n        // It's good practice to create the expected value once.\n        let expected_address = name.to_string();\n\n        // Check for inequality and panic with a detailed message if they don't match.\n        assert_eq!(received_address, &expected_address);\n    }\n\n    fn move_subchannel_to_state(\n        lb_policy: &mut dyn LbPolicy,\n        subchannel: Arc<dyn Subchannel>,\n        tcc: &mut dyn ChannelController,\n        state: ConnectivityState,\n    ) {\n        lb_policy.subchannel_update(\n            subchannel,\n            &SubchannelState {\n                connectivity_state: state,\n                ..Default::default()\n            },\n            tcc,\n        );\n    }\n\n    // Tests that the gracefulswitch policy correctly sets a child and sends\n    // updates to that child when it receives its first config.\n    #[tokio::test]\n    async fn gracefulswitch_successful_first_update() {\n        reg_stub_policy(\n            \"stub-gracefulswitch_successful_first_update-one\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_successful_first_update-one\",\n            ),\n        );\n        reg_stub_policy(\n            \"stub-gracefulswitch_successful_first_update-two\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_successful_first_update-two\",\n            ),\n        );\n\n        let (mut rx_events, mut graceful_switch, mut tcc) = setup();\n        let service_config = serde_json::json!([\n                { \"stub-gracefulswitch_successful_first_update-one\": serde_json::json!({}) },\n                { \"stub-gracefulswitch_successful_first_update-two\": serde_json::json!({}) }\n            ]\n        );\n\n        let parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config,\n        })\n        .unwrap();\n\n        let endpoint = create_endpoint_with_one_address(\"127.0.0.1:1234\".to_string());\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint.clone()]),\n            ..Default::default()\n        };\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config), &mut *tcc)\n            .unwrap();\n\n        let subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_successful_first_update-one\",\n        )\n        .await;\n    }\n\n    // Tests that the gracefulswitch policy correctly sets a pending child and\n    // sends subchannel updates to that child when it receives a new config.\n    #[tokio::test]\n    async fn gracefulswitch_switching_to_resolver_update() {\n        let (mut rx_events, mut graceful_switch, mut tcc) = setup();\n        reg_stub_policy(\n            \"stub-gracefulswitch_switching_to_resolver_update-one\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_switching_to_resolver_update-one\",\n            ),\n        );\n        reg_stub_policy(\n            \"stub-gracefulswitch_switching_to_resolver_update-two\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_switching_to_resolver_update-two\",\n            ),\n        );\n\n        let service_config = serde_json::json!([\n                { \"stub-gracefulswitch_switching_to_resolver_update-one\": serde_json::json!({}) }\n            ]\n        );\n        let parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config,\n        })\n        .unwrap();\n\n        let endpoint = create_endpoint_with_one_address(\"127.0.0.1:1234\".to_string());\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint.clone()]),\n            ..Default::default()\n        };\n\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config), &mut *tcc)\n            .unwrap();\n\n        // Subchannel creation and ready\n        let subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n\n        // Assert picker is TestPickerOne by checking subchannel address\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_switching_to_resolver_update-one\",\n        )\n        .await;\n\n        // 2. Switch to mock_policy_two as pending\n        let new_service_config = serde_json::json!([\n                { \"stub-gracefulswitch_switching_to_resolver_update-two\": serde_json::json!({}) }\n            ]\n        );\n        let new_parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: new_service_config,\n        })\n        .unwrap();\n        graceful_switch\n            .resolver_update(update.clone(), Some(&new_parsed_config), &mut *tcc)\n            .unwrap();\n\n        // Simulate subchannel creation and ready for pending\n        let subchannel_two = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            subchannel_two,\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        // Assert picker is TestPickerTwo by checking subchannel address\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_switching_to_resolver_update-two\",\n        )\n        .await;\n        assert_channel_empty(&mut rx_events).await;\n    }\n\n    async fn assert_channel_empty(rx_events: &mut UnboundedReceiver<TestEvent>) {\n        select! {\n            event = rx_events.recv() => {\n                panic!(\"Received unexpected event from policy: {event:?}\");\n            }\n            _ = tokio::time::sleep(DEFAULT_TEST_SHORT_TIMEOUT) => {}\n        };\n    }\n\n    // Tests that the gracefulswitch policy should do nothing when it receives a\n    // new config of the same policy that it received before.\n    #[tokio::test]\n    async fn gracefulswitch_two_policies_same_type() {\n        let (mut rx_events, mut graceful_switch, mut tcc) = setup();\n        reg_stub_policy(\n            \"stub-gracefulswitch_two_policies_same_type-one\",\n            create_funcs_for_gracefulswitch_tests(\"stub-gracefulswitch_two_policies_same_type-one\"),\n        );\n        let service_config = serde_json::json!(\n            [\n                { \"stub-gracefulswitch_two_policies_same_type-one\": serde_json::json!({}) }\n            ]\n        );\n        let parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config,\n        })\n        .unwrap();\n        let endpoint = create_endpoint_with_one_address(\"127.0.0.1:1234\".to_string());\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint.clone()]),\n            ..Default::default()\n        };\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config), &mut *tcc)\n            .unwrap();\n        let subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_two_policies_same_type-one\",\n        )\n        .await;\n\n        let service_config2 = serde_json::json!(\n            [\n                { \"stub-gracefulswitch_two_policies_same_type-one\": serde_json::json!({}) }\n            ]\n        );\n        let parsed_config2 = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config2,\n        })\n        .unwrap();\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config2), &mut *tcc)\n            .unwrap();\n        let subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        assert_eq!(&*subchannel.address().address, \"127.0.0.1:1234\");\n        assert_channel_empty(&mut rx_events).await;\n    }\n\n    // Tests that the gracefulswitch policy should replace the current child\n    // with the pending child if the current child isn't ready.\n    #[tokio::test]\n    async fn gracefulswitch_current_not_ready_pending_update() {\n        let (mut rx_events, mut graceful_switch, mut tcc) = setup();\n        reg_stub_policy(\n            \"stub-gracefulswitch_current_not_ready_pending_update-one\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_current_not_ready_pending_update-one\",\n            ),\n        );\n        reg_stub_policy(\n            \"stub-gracefulswitch_current_not_ready_pending_update-two\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_current_not_ready_pending_update-two\",\n            ),\n        );\n\n        let service_config = serde_json::json!([\n                { \"stub-gracefulswitch_current_not_ready_pending_update-one\": serde_json::json!({}) }\n            ]\n        );\n\n        let parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config,\n        })\n        .unwrap();\n\n        let endpoint = create_endpoint_with_one_address(\"127.0.0.1:1234\".to_string());\n        let second_endpoint = create_endpoint_with_one_address(\"0.0.0.0.0\".to_string());\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint.clone()]),\n            ..Default::default()\n        };\n\n        // Switch to first one (current)\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config), &mut *tcc)\n            .unwrap();\n\n        let current_subchannels = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        assert_channel_empty(&mut rx_events).await;\n\n        let new_service_config = serde_json::json!([\n                { \"stub-gracefulswitch_current_not_ready_pending_update-two\": serde_json::json!({ \"shuffleAddressList\": false }) },\n            ]\n        );\n        let second_update = ResolverUpdate {\n            endpoints: Ok(vec![second_endpoint.clone()]),\n            ..Default::default()\n        };\n        let new_parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: new_service_config,\n        })\n        .unwrap();\n        graceful_switch\n            .resolver_update(second_update.clone(), Some(&new_parsed_config), &mut *tcc)\n            .unwrap();\n\n        let second_subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        assert_channel_empty(&mut rx_events).await;\n\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            second_subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_current_not_ready_pending_update-two\",\n        )\n        .await;\n        assert_channel_empty(&mut rx_events).await;\n    }\n\n    // Tests that the gracefulswitch policy should replace the current child\n    // with the pending child if the current child was ready but then leaves ready.\n    #[tokio::test]\n    async fn gracefulswitch_current_leaving_ready() {\n        let (mut rx_events, mut graceful_switch, mut tcc) = setup();\n        reg_stub_policy(\n            \"stub-gracefulswitch_current_leaving_ready-one\",\n            create_funcs_for_gracefulswitch_tests(\"stub-gracefulswitch_current_leaving_ready-one\"),\n        );\n        reg_stub_policy(\n            \"stub-gracefulswitch_current_leaving_ready-two\",\n            create_funcs_for_gracefulswitch_tests(\"stub-gracefulswitch_current_leaving_ready-two\"),\n        );\n        let service_config = serde_json::json!([\n                { \"stub-gracefulswitch_current_leaving_ready-one\": serde_json::json!({}) }\n            ]\n        );\n        let parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config,\n        })\n        .unwrap();\n\n        let endpoint = create_endpoint_with_one_address(\"127.0.0.1:1234\".to_string());\n        let endpoint2 = create_endpoint_with_one_address(\"127.0.0.1:1235\".to_string());\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint.clone()]),\n            ..Default::default()\n        };\n\n        // Switch to first one (current)\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config), &mut *tcc)\n            .unwrap();\n\n        let current_subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            current_subchannel.clone(),\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_current_leaving_ready-one\",\n        )\n        .await;\n        let new_service_config = serde_json::json!(\n            [\n                { \"stub-gracefulswitch_current_leaving_ready-two\": serde_json::json!({}) },\n\n            ]\n        );\n        let new_update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint2.clone()]),\n            ..Default::default()\n        };\n        let new_parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: new_service_config,\n        })\n        .unwrap();\n        graceful_switch\n            .resolver_update(new_update.clone(), Some(&new_parsed_config), &mut *tcc)\n            .unwrap();\n\n        let pending_subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            pending_subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Connecting,\n        );\n        // This should not produce an update.\n        assert_channel_empty(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            current_subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Connecting,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_current_leaving_ready-two\",\n        )\n        .await;\n    }\n\n    // Tests that the gracefulswitch policy should replace the current child\n    // with the pending child if the pending child leaves connecting.\n    #[tokio::test]\n    async fn gracefulswitch_pending_leaving_connecting() {\n        let (mut rx_events, mut graceful_switch, mut tcc) = setup();\n        reg_stub_policy(\n            \"stub-gracefulswitch_current_leaving_ready-one\",\n            create_funcs_for_gracefulswitch_tests(\"stub-gracefulswitch_current_leaving_ready-one\"),\n        );\n        reg_stub_policy(\n            \"stub-gracefulswitch_current_leaving_ready-two\",\n            create_funcs_for_gracefulswitch_tests(\"stub-gracefulswitch_current_leaving_ready-two\"),\n        );\n        let service_config = serde_json::json!(\n            [\n                { \"stub-gracefulswitch_current_leaving_ready-one\": serde_json::json!({}) }\n            ]\n        );\n        let parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config,\n        })\n        .unwrap();\n        let endpoint = create_endpoint_with_one_address(\"127.0.0.1:1234\".to_string());\n        let endpoint2 = create_endpoint_with_one_address(\"127.0.0.1:1235\".to_string());\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint.clone()]),\n            ..Default::default()\n        };\n\n        // Switch to first one (current)\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config), &mut *tcc)\n            .unwrap();\n\n        let current_subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            current_subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_current_leaving_ready-one\",\n        )\n        .await;\n        let new_service_config = serde_json::json!(\n            [\n                { \"stub-gracefulswitch_current_leaving_ready-two\": serde_json::json!({}) },\n            ]\n        );\n        let new_update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint2.clone()]),\n            ..Default::default()\n        };\n        let new_parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: new_service_config,\n        })\n        .unwrap();\n\n        graceful_switch\n            .resolver_update(new_update.clone(), Some(&new_parsed_config), &mut *tcc)\n            .unwrap();\n\n        let pending_subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            pending_subchannel.clone(),\n            tcc.as_mut(),\n            ConnectivityState::TransientFailure,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_current_leaving_ready-two\",\n        )\n        .await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            pending_subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Connecting,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_current_leaving_ready-two\",\n        )\n        .await;\n    }\n\n    // Tests that the gracefulswitch policy should remove the current child's\n    // subchannels after swapping.\n    #[tokio::test]\n    async fn gracefulswitch_subchannels_removed_after_current_child_swapped() {\n        let (mut rx_events, mut graceful_switch, mut tcc) = setup();\n        reg_stub_policy(\n            \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-one\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-one\",\n            ),\n        );\n        reg_stub_policy(\n            \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-two\",\n            create_funcs_for_gracefulswitch_tests(\n                \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-two\",\n            ),\n        );\n        let service_config = serde_json::json!(\n            [\n                { \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-one\": serde_json::json!({}) }\n            ]\n        );\n        let parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: service_config,\n        })\n        .unwrap();\n        let endpoint = create_endpoint_with_one_address(\"127.0.0.1:1234\".to_string());\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![endpoint.clone()]),\n            ..Default::default()\n        };\n        graceful_switch\n            .resolver_update(update.clone(), Some(&parsed_config), &mut *tcc)\n            .unwrap();\n\n        let current_subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            current_subchannel.clone(),\n            tcc.as_mut(),\n            ConnectivityState::Ready,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-one\",\n        )\n        .await;\n        let new_service_config = serde_json::json!(\n            [\n                { \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-two\": serde_json::json!({ \"shuffleAddressList\": false }) },\n            ]\n        );\n        let second_endpoint = create_endpoint_with_one_address(\"127.0.0.1:1235\".to_string());\n        let second_update = ResolverUpdate {\n            endpoints: Ok(vec![second_endpoint.clone()]),\n            ..Default::default()\n        };\n        let new_parsed_config = GracefulSwitchPolicy::parse_config(&ParsedJsonLbConfig {\n            value: new_service_config,\n        })\n        .unwrap();\n        graceful_switch\n            .resolver_update(second_update.clone(), Some(&new_parsed_config), &mut *tcc)\n            .unwrap();\n        let pending_subchannel = verify_subchannel_creation_from_policy(&mut rx_events).await;\n        println!(\"moving subchannel to idle\");\n        move_subchannel_to_state(\n            &mut *graceful_switch,\n            pending_subchannel,\n            tcc.as_mut(),\n            ConnectivityState::Idle,\n        );\n        verify_correct_picker_from_policy(\n            &mut rx_events,\n            \"stub-gracefulswitch_subchannels_removed_after_current_child_swapped-two\",\n        )\n        .await;\n        assert!(Arc::strong_count(&current_subchannel) == 1);\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/load_balancing/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse core::panic;\nuse std::any::Any;\nuse std::error::Error;\nuse std::fmt::Debug;\nuse std::fmt::Display;\nuse std::hash::Hash;\nuse std::hash::Hasher;\nuse std::ptr::addr_eq;\nuse std::sync::Arc;\nuse std::sync::Mutex;\nuse std::sync::Weak;\n\nuse tonic::Status;\nuse tonic::metadata::MetadataMap;\n\nuse crate::client::ConnectivityState;\nuse crate::client::channel::InternalChannelController;\nuse crate::client::channel::WorkQueueItem;\nuse crate::client::channel::WorkQueueTx;\nuse crate::client::name_resolution::Address;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::client::service_config::LbConfig;\nuse crate::client::subchannel::InternalSubchannel;\nuse crate::client::subchannel::SubchannelStateWatcher;\nuse crate::core::RequestHeaders;\nuse crate::rt::GrpcRuntime;\n\npub(crate) mod child_manager;\npub(crate) mod graceful_switch;\npub(crate) mod pick_first;\npub(crate) mod round_robin;\n\n#[cfg(test)]\npub(crate) mod test_utils;\n\npub(crate) mod registry;\npub(crate) use registry::GLOBAL_LB_REGISTRY;\n\n/// A collection of data configured on the channel that is constructing this\n/// LbPolicy.\n#[derive(Debug)]\npub(crate) struct LbPolicyOptions {\n    /// A hook into the channel's work scheduler that allows the LbPolicy to\n    /// request the ability to perform operations on the ChannelController.\n    pub work_scheduler: Arc<dyn WorkScheduler>,\n    pub runtime: GrpcRuntime,\n}\n\n/// Used to asynchronously request a call into the LbPolicy's work method if\n/// the LbPolicy needs to provide an update without waiting for an update\n/// from the channel first.\npub(crate) trait WorkScheduler: Send + Sync + Debug {\n    // Schedules a call into the LbPolicy's work method.  If there is already a\n    // pending work call that has not yet started, this may not schedule another\n    // call.\n    fn schedule_work(&self);\n}\n\n/// Abstract representation of the configuration for any LB policy, stored as\n/// JSON.  Hides internal storage details and includes a method to deserialize\n/// the JSON into a concrete policy struct.\n#[derive(Debug)]\npub(crate) struct ParsedJsonLbConfig {\n    value: serde_json::Value,\n}\n\nimpl ParsedJsonLbConfig {\n    /// Creates a new ParsedJsonLbConfig from the provided JSON string.\n    pub fn new(json: &str) -> Result<Self, String> {\n        match serde_json::from_str(json) {\n            Ok(value) => Ok(ParsedJsonLbConfig { value }),\n            Err(e) => Err(format!(\"failed to parse LB config JSON: {e}\")),\n        }\n    }\n\n    pub(crate) fn from_value(value: serde_json::Value) -> Self {\n        Self { value }\n    }\n\n    /// Converts the JSON configuration into a concrete type that represents the\n    /// configuration of an LB policy.\n    ///\n    /// This will typically be used by the LB policy builder to parse the\n    /// configuration into a type that can be used by the LB policy.\n    pub fn convert_to<T: serde::de::DeserializeOwned>(\n        &self,\n    ) -> Result<T, Box<dyn Error + Send + Sync>> {\n        let res: T = match serde_json::from_value(self.value.clone()) {\n            Ok(v) => v,\n            Err(e) => {\n                return Err(format!(\"{e}\").into());\n            }\n        };\n        Ok(res)\n    }\n}\n\n/// An LB policy factory that produces LbPolicy instances used by the channel\n/// to manage connections and pick connections for RPCs.\npub(crate) trait LbPolicyBuilder: Send + Sync + Debug {\n    /// Builds and returns a new LB policy instance.\n    ///\n    /// Note that build must not fail.  Any optional configuration is delivered\n    /// via the LbPolicy's resolver_update method.\n    ///\n    /// An LbPolicy instance is assumed to begin in a Connecting state that\n    /// queues RPCs until its first update.\n    fn build(&self, options: LbPolicyOptions) -> Box<dyn LbPolicy>;\n\n    /// Reports the name of the LB Policy.\n    fn name(&self) -> &'static str;\n\n    /// Parses the JSON LB policy configuration into an internal representation.\n    ///\n    /// LB policies do not need to accept a configuration, in which case the\n    /// default implementation returns Ok(None).\n    fn parse_config(\n        &self,\n        _config: &ParsedJsonLbConfig,\n    ) -> Result<Option<LbConfig>, Box<dyn Error + Send + Sync>> {\n        Ok(None)\n    }\n}\n\n/// An LB policy instance.\n///\n/// LB policies are responsible for creating connections (modeled as\n/// Subchannels) and producing Picker instances for picking connections for\n/// RPCs.\npub(crate) trait LbPolicy: Send + Debug {\n    /// Called by the channel when the name resolver produces a new set of\n    /// resolved addresses or a new service config.\n    fn resolver_update(\n        &mut self,\n        update: ResolverUpdate,\n        config: Option<&LbConfig>,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>>;\n\n    /// Called by the channel when any subchannel created by the LB policy\n    /// changes state.\n    fn subchannel_update(\n        &mut self,\n        subchannel: Arc<dyn Subchannel>,\n        state: &SubchannelState,\n        channel_controller: &mut dyn ChannelController,\n    );\n\n    /// Called by the channel in response to a call from the LB policy to the\n    /// WorkScheduler's request_work method.\n    fn work(&mut self, channel_controller: &mut dyn ChannelController);\n\n    /// Called by the channel when an LbPolicy goes idle and the channel\n    /// wants it to start connecting to subchannels again.\n    fn exit_idle(&mut self, channel_controller: &mut dyn ChannelController);\n}\n\n/// Controls channel behaviors.\npub(crate) trait ChannelController: Send + Sync {\n    /// Creates a new subchannel in IDLE state.\n    fn new_subchannel(&mut self, address: &Address) -> Arc<dyn Subchannel>;\n\n    /// Provides a new snapshot of the LB policy's state to the channel.\n    fn update_picker(&mut self, update: LbState);\n\n    /// Signals the name resolver to attempt to re-resolve addresses.  Typically\n    /// used when connections fail, indicating a possible change in the overall\n    /// network configuration.\n    fn request_resolution(&mut self);\n}\n\n/// Represents the current state of a Subchannel.\n#[derive(Debug, Clone)]\npub(crate) struct SubchannelState {\n    /// The connectivity state of the subchannel.  See SubChannel for a\n    /// description of the various states and their valid transitions.\n    pub connectivity_state: ConnectivityState,\n    // Set if connectivity state is TransientFailure to describe the most recent\n    // connection error.  None for any other connectivity_state value.\n    pub last_connection_error: Option<Arc<dyn Error + Send + Sync>>,\n}\n\nimpl Default for SubchannelState {\n    fn default() -> Self {\n        Self {\n            connectivity_state: ConnectivityState::Idle,\n            last_connection_error: None,\n        }\n    }\n}\n\nimpl Display for SubchannelState {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"connectivity_state: {}\", self.connectivity_state)?;\n        if let Some(err) = &self.last_connection_error {\n            write!(f, \", last_connection_error: {err}\")?;\n        }\n        Ok(())\n    }\n}\n\n/// A Picker is responsible for deciding what Subchannel to use for any given\n/// request.  A Picker is only used once for any RPC.  If pick() returns Queue,\n/// the channel will queue the RPC until a new Picker is produced by the\n/// LbPolicy, and will call pick() on the new Picker for the request.\n///\n/// Pickers are always paired with a ConnectivityState which the channel will\n/// expose to applications so they can predict what might happens when\n/// performing RPCs:\n///\n/// If the ConnectivityState is Idle, the Picker should ensure connections are\n/// initiated by the LbPolicy that produced the Picker, and return a Queue\n/// result so the request is attempted the next time a Picker is produced.\n///\n/// If the ConnectivityState is Connecting, the Picker should return a Queue\n/// result and continue to wait for pending connections.\n///\n/// If the ConnectivityState is Ready, the Picker should return a Ready\n/// Subchannel.\n///\n/// If the ConnectivityState is TransientFailure, the Picker should return an\n/// Err with an error that describes why connections are failing.\npub(crate) trait Picker: Send + Sync + Debug {\n    /// Picks a connection to use for the request.\n    ///\n    /// This function should not block.  If the Picker needs to do blocking or\n    /// time-consuming work to service this request, it should return Queue, and\n    /// the Pick call will be repeated by the channel when a new Picker is\n    /// produced by the LbPolicy.\n    fn pick(&self, request: &RequestHeaders) -> PickResult;\n}\n\n#[derive(Debug)]\npub(crate) enum PickResult {\n    /// Indicates the Subchannel in the Pick should be used for the request.\n    Pick(Pick),\n    /// Indicates the LbPolicy is attempting to connect to a server to use for\n    /// the request.\n    Queue,\n    /// Indicates that the request should fail with the included error status\n    /// (with the code converted to UNAVAILABLE).  If the RPC is wait-for-ready,\n    /// then it will not be terminated, but instead attempted on a new picker if\n    /// one is produced before it is cancelled.\n    Fail(Status),\n    /// Indicates that the request should fail with the included status\n    /// immediately, even if the RPC is wait-for-ready.  The channel will\n    /// convert the status code to INTERNAL if it is not a valid code for the\n    /// gRPC library to produce, per [gRFC A54].\n    ///\n    /// [gRFC A54]:\n    ///     https://github.com/grpc/proposal/blob/master/A54-restrict-control-plane-status-codes.md\n    Drop(Status),\n}\n\nimpl PickResult {\n    pub fn unwrap_pick(self) -> Pick {\n        let PickResult::Pick(pick) = self else {\n            panic!(\"Called `PickResult::unwrap_pick` on a `Queue` or `Err` value\");\n        };\n        pick\n    }\n}\n\nimpl PartialEq for PickResult {\n    fn eq(&self, other: &Self) -> bool {\n        match self {\n            PickResult::Pick(pick) => match other {\n                PickResult::Pick(other_pick) => pick.subchannel == other_pick.subchannel.clone(),\n                _ => false,\n            },\n            PickResult::Queue => matches!(other, PickResult::Queue),\n            PickResult::Fail(status) => {\n                // TODO: implement me.\n                false\n            }\n            PickResult::Drop(status) => {\n                // TODO: implement me.\n                false\n            }\n        }\n    }\n}\n\nimpl Display for PickResult {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Pick(_) => write!(f, \"Pick\"),\n            Self::Queue => write!(f, \"Queue\"),\n            Self::Fail(st) => write!(f, \"Fail({st})\"),\n            Self::Drop(st) => write!(f, \"Drop({st})\"),\n        }\n    }\n}\n/// Data provided by the LB policy.\n#[derive(Clone, Debug)]\npub(crate) struct LbState {\n    pub connectivity_state: super::ConnectivityState,\n    pub picker: Arc<dyn Picker>,\n}\n\nimpl PartialEq for LbState {\n    /// Equality for two LbStates.\n    ///\n    /// Two `LbState`s are equal if and only if they have the same connectivity\n    /// state and the same Picker allocation.  Even if two Pickers have the same\n    /// behavior or the same underlying implementation, they will be considered\n    /// distinct unless they are the same Picker instance.\n    fn eq(&self, other: &Self) -> bool {\n        self.connectivity_state == other.connectivity_state\n            && std::ptr::addr_eq(Arc::as_ptr(&self.picker), Arc::as_ptr(&other.picker))\n    }\n}\n\nimpl Eq for LbState {}\n\nimpl LbState {\n    /// Returns a generic initial LbState which is Connecting and a picker which\n    /// queues all picks.\n    pub fn initial() -> Self {\n        Self {\n            connectivity_state: ConnectivityState::Connecting,\n            picker: Arc::new(QueuingPicker {}),\n        }\n    }\n}\n\n/// Type alias for the completion callback function.\npub(crate) type CompletionCallback = Box<dyn Fn() + Send + Sync>;\n\n/// A collection of data used by the channel for routing a request.\npub(crate) struct Pick {\n    /// The Subchannel for the request.\n    pub subchannel: Arc<dyn Subchannel>,\n    // Metadata to be added to existing outgoing metadata.\n    pub metadata: MetadataMap,\n    // Callback to be invoked once the RPC completes.\n    pub on_complete: Option<CompletionCallback>,\n}\n\nimpl Debug for Pick {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Pick\")\n            .field(\"subchannel\", &self.subchannel)\n            .field(\"metadata\", &self.metadata)\n            .field(\"on_complete\", &format_args!(\"{:p}\", &self.on_complete))\n            .finish()\n    }\n}\n\npub(crate) trait DynHash {\n    #[allow(clippy::redundant_allocation)]\n    fn dyn_hash(&self, state: &mut Box<&mut dyn Hasher>);\n}\n\nimpl<T: Hash> DynHash for T {\n    fn dyn_hash(&self, state: &mut Box<&mut dyn Hasher>) {\n        self.hash(state);\n    }\n}\n\npub(crate) trait DynPartialEq {\n    fn dyn_eq(&self, other: &&dyn Any) -> bool;\n}\n\nimpl<T: Eq + PartialEq + 'static> DynPartialEq for T {\n    fn dyn_eq(&self, other: &&dyn Any) -> bool {\n        let Some(other) = other.downcast_ref::<T>() else {\n            return false;\n        };\n        self.eq(other)\n    }\n}\n\nmod private {\n    pub trait Sealed {}\n}\n\npub(crate) trait SealedSubchannel: private::Sealed {}\n\n/// A Subchannel represents a method of communicating with a server which may be\n/// connected or disconnected many times across its lifetime.\n///\n/// - Subchannels start IDLE.\n///\n/// - IDLE transitions to CONNECTING when connect() is called.\n///\n/// - CONNECTING transitions to READY on success or TRANSIENT_FAILURE on error.\n///\n/// - READY transitions to IDLE when the connection is lost.\n///\n/// - TRANSIENT_FAILURE transitions to IDLE when the reconnect backoff timer has\n///   expired.  This timer scales exponentially and is reset when the subchannel\n///   becomes READY.\n///\n/// When a Subchannel is dropped, it is disconnected automatically, and no\n/// subsequent state updates will be provided for it to the LB policy.\npub(crate) trait Subchannel:\n    SealedSubchannel + DynHash + DynPartialEq + Any + Send + Sync\n{\n    /// Returns the address of the Subchannel.\n    /// TODO: Consider whether this should really be public.\n    fn address(&self) -> Address;\n\n    /// Notifies the Subchannel to connect.\n    fn connect(&self);\n}\n\nimpl dyn Subchannel {\n    pub fn downcast_ref<T>(&self) -> Option<&T>\n    where\n        T: 'static,\n    {\n        (self as &dyn Any).downcast_ref()\n    }\n}\n\nimpl Hash for dyn Subchannel {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.dyn_hash(&mut Box::new(state as &mut dyn Hasher));\n    }\n}\n\nimpl PartialEq for dyn Subchannel {\n    fn eq(&self, other: &Self) -> bool {\n        self.dyn_eq(&Box::new(other as &dyn Any))\n    }\n}\n\nimpl Eq for dyn Subchannel {}\n\nimpl Debug for dyn Subchannel {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"Subchannel: {}\", self.address())\n    }\n}\n\nimpl Display for dyn Subchannel {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"Subchannel: {}\", self.address())\n    }\n}\n\n#[derive(Debug)]\nstruct WeakSubchannel(Weak<dyn Subchannel>);\n\nimpl From<Arc<dyn Subchannel>> for WeakSubchannel {\n    fn from(subchannel: Arc<dyn Subchannel>) -> Self {\n        WeakSubchannel(Arc::downgrade(&subchannel))\n    }\n}\n\nimpl WeakSubchannel {\n    pub fn new(subchannel: &Arc<dyn Subchannel>) -> Self {\n        WeakSubchannel(Arc::downgrade(subchannel))\n    }\n\n    pub fn upgrade(&self) -> Option<Arc<dyn Subchannel>> {\n        self.0.upgrade()\n    }\n}\n\nimpl Hash for WeakSubchannel {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        (self.0.as_ptr() as *const () as usize).hash(state);\n    }\n}\n\nimpl PartialEq for WeakSubchannel {\n    fn eq(&self, other: &Self) -> bool {\n        addr_eq(self.0.as_ptr(), other.0.as_ptr())\n    }\n}\n\nimpl Eq for WeakSubchannel {}\n\npub(crate) struct ExternalSubchannel {\n    pub(crate) isc: Option<Arc<InternalSubchannel>>,\n    work_scheduler: WorkQueueTx,\n    watcher: Mutex<Option<Arc<SubchannelStateWatcher>>>,\n}\n\nimpl ExternalSubchannel {\n    pub(super) fn new(isc: Arc<InternalSubchannel>, work_scheduler: WorkQueueTx) -> Self {\n        ExternalSubchannel {\n            isc: Some(isc),\n            work_scheduler,\n            watcher: Mutex::default(),\n        }\n    }\n\n    pub(super) fn set_watcher(&self, watcher: Arc<SubchannelStateWatcher>) {\n        self.watcher.lock().unwrap().replace(watcher);\n    }\n}\n\nimpl Hash for ExternalSubchannel {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.address().hash(state);\n    }\n}\n\nimpl PartialEq for ExternalSubchannel {\n    fn eq(&self, other: &Self) -> bool {\n        self.address() == other.address()\n    }\n}\n\nimpl Eq for ExternalSubchannel {}\n\nimpl Subchannel for ExternalSubchannel {\n    fn address(&self) -> Address {\n        self.isc.as_ref().unwrap().address()\n    }\n\n    fn connect(&self) {\n        println!(\"connect called for subchannel: {self}\");\n        self.isc.as_ref().unwrap().connect();\n    }\n}\n\nimpl SealedSubchannel for ExternalSubchannel {}\nimpl private::Sealed for ExternalSubchannel {}\n\nimpl Drop for ExternalSubchannel {\n    fn drop(&mut self) {\n        let watcher = self.watcher.lock().unwrap().take();\n        let address = self.address().address.clone();\n        let isc = self.isc.take();\n        let _ = self.work_scheduler.send(WorkQueueItem::Closure(Box::new(\n            move |c: &mut InternalChannelController| {\n                println!(\"unregistering connectivity state watcher for {address:?}\");\n                isc.as_ref()\n                    .unwrap()\n                    .unregister_connectivity_state_watcher(watcher.unwrap());\n            },\n            // The internal subchannel is dropped from here (i.e., from inside\n            // the work serializer), if this is the last reference to it.\n        )));\n    }\n}\n\nimpl Debug for ExternalSubchannel {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"Subchannel {}\", self.address())\n    }\n}\n\nimpl Display for ExternalSubchannel {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"Subchannel {}\", self.address())\n    }\n}\n\npub(crate) trait ForwardingSubchannel: DynHash + DynPartialEq + Any + Send + Sync {\n    fn delegate(&self) -> Arc<dyn Subchannel>;\n\n    fn address(&self) -> Address {\n        self.delegate().address()\n    }\n    fn connect(&self) {\n        self.delegate().connect()\n    }\n}\n\nimpl<T: ForwardingSubchannel> Subchannel for T {\n    fn address(&self) -> Address {\n        self.address()\n    }\n    fn connect(&self) {\n        self.connect()\n    }\n}\nimpl<T: ForwardingSubchannel> SealedSubchannel for T {}\nimpl<T: ForwardingSubchannel> private::Sealed for T {}\n\n/// QueuingPicker always returns Queue.  LB policies that are not actively\n/// Connecting should not use this picker.\n#[derive(Debug)]\npub(crate) struct QueuingPicker {}\n\nimpl Picker for QueuingPicker {\n    fn pick(&self, _request: &RequestHeaders) -> PickResult {\n        PickResult::Queue\n    }\n}\n\n#[derive(Debug)]\npub(crate) struct FailingPicker {\n    pub error: String,\n}\n\nimpl Picker for FailingPicker {\n    fn pick(&self, _: &RequestHeaders) -> PickResult {\n        PickResult::Fail(Status::unavailable(self.error.clone()))\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/load_balancing/pick_first.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::error::Error;\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse tonic::metadata::MetadataMap;\n\nuse crate::client::ConnectivityState;\nuse crate::client::load_balancing::ChannelController;\nuse crate::client::load_balancing::LbConfig;\nuse crate::client::load_balancing::LbPolicy;\nuse crate::client::load_balancing::LbPolicyBuilder;\nuse crate::client::load_balancing::LbPolicyOptions;\nuse crate::client::load_balancing::LbState;\nuse crate::client::load_balancing::Pick;\nuse crate::client::load_balancing::PickResult;\nuse crate::client::load_balancing::Picker;\nuse crate::client::load_balancing::Subchannel;\nuse crate::client::load_balancing::SubchannelState;\nuse crate::client::load_balancing::WorkScheduler;\nuse crate::client::name_resolution::Address;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::core::RequestHeaders;\nuse crate::rt::GrpcRuntime;\n\npub(crate) static POLICY_NAME: &str = \"pick_first\";\n\n#[derive(Debug)]\nstruct Builder {}\n\nimpl LbPolicyBuilder for Builder {\n    fn build(&self, options: LbPolicyOptions) -> Box<dyn LbPolicy> {\n        Box::new(PickFirstPolicy {\n            work_scheduler: options.work_scheduler,\n            subchannel: None,\n            next_addresses: Vec::default(),\n            runtime: options.runtime,\n        })\n    }\n\n    fn name(&self) -> &'static str {\n        POLICY_NAME\n    }\n}\n\npub(crate) fn reg() {\n    super::GLOBAL_LB_REGISTRY.add_builder(Builder {})\n}\n\n#[derive(Debug)]\nstruct PickFirstPolicy {\n    work_scheduler: Arc<dyn WorkScheduler>,\n    subchannel: Option<Arc<dyn Subchannel>>,\n    next_addresses: Vec<Address>,\n    runtime: GrpcRuntime,\n}\n\nimpl LbPolicy for PickFirstPolicy {\n    fn resolver_update(\n        &mut self,\n        update: ResolverUpdate,\n        config: Option<&LbConfig>,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        let mut addresses = update\n            .endpoints\n            .unwrap()\n            .into_iter()\n            .next()\n            .ok_or(\"no endpoints\")?\n            .addresses;\n\n        let address = addresses.pop().ok_or(\"no addresses\")?;\n\n        let sc = channel_controller.new_subchannel(&address);\n        sc.connect();\n        self.subchannel = Some(sc);\n\n        self.next_addresses = addresses;\n        let work_scheduler = self.work_scheduler.clone();\n        let runtime = self.runtime.clone();\n        // TODO: Implement Drop that cancels this task.\n        self.runtime.spawn(Box::pin(async move {\n            runtime.sleep(Duration::from_millis(200)).await;\n            work_scheduler.schedule_work();\n        }));\n        // TODO: return a picker that queues RPCs.\n        Ok(())\n    }\n\n    fn subchannel_update(\n        &mut self,\n        subchannel: Arc<dyn Subchannel>,\n        state: &SubchannelState,\n        channel_controller: &mut dyn ChannelController,\n    ) {\n        // Assume the update is for our subchannel.\n        if state.connectivity_state == ConnectivityState::Ready {\n            channel_controller.update_picker(LbState {\n                connectivity_state: ConnectivityState::Ready,\n                picker: Arc::new(OneSubchannelPicker {\n                    sc: self.subchannel.as_ref().unwrap().clone(),\n                }),\n            });\n        }\n    }\n\n    fn work(&mut self, channel_controller: &mut dyn ChannelController) {}\n\n    fn exit_idle(&mut self, _channel_controller: &mut dyn ChannelController) {\n        todo!(\"implement exit_idle\")\n    }\n}\n\n#[derive(Debug)]\nstruct OneSubchannelPicker {\n    sc: Arc<dyn Subchannel>,\n}\n\nimpl Picker for OneSubchannelPicker {\n    fn pick(&self, _: &RequestHeaders) -> PickResult {\n        PickResult::Pick(Pick {\n            subchannel: self.sc.clone(),\n            // on_complete: None,\n            metadata: MetadataMap::new(),\n            on_complete: None,\n        })\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/load_balancing/registry.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::collections::HashMap;\nuse std::sync::Arc;\nuse std::sync::LazyLock;\nuse std::sync::Mutex;\n\nuse crate::client::load_balancing::LbPolicyBuilder;\n\n/// A registry to store and retrieve LB policies.  LB policies are indexed by\n/// their names.\npub(crate) struct LbPolicyRegistry {\n    m: Arc<Mutex<HashMap<String, Arc<dyn LbPolicyBuilder>>>>,\n}\n\nimpl LbPolicyRegistry {\n    /// Construct an empty LB policy registry.\n    pub fn new() -> Self {\n        Self { m: Arc::default() }\n    }\n    /// Add a LB policy into the registry.\n    pub(crate) fn add_builder(&self, builder: impl LbPolicyBuilder + 'static) {\n        self.m\n            .lock()\n            .unwrap()\n            .insert(builder.name().to_string(), Arc::new(builder));\n    }\n    /// Retrieve a LB policy from the registry, or None if not found.\n    pub(crate) fn get_policy(&self, name: &str) -> Option<Arc<dyn LbPolicyBuilder>> {\n        self.m.lock().unwrap().get(name).cloned()\n    }\n}\n\nimpl Default for LbPolicyRegistry {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// The registry used if a local registry is not provided to a channel or if it\n/// does not exist in the local registry.\npub(crate) static GLOBAL_LB_REGISTRY: LazyLock<LbPolicyRegistry> =\n    LazyLock::new(LbPolicyRegistry::new);\n"
  },
  {
    "path": "grpc/src/client/load_balancing/round_robin.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::error::Error;\nuse std::sync::Arc;\nuse std::sync::Once;\nuse std::sync::atomic::AtomicUsize;\nuse std::sync::atomic::Ordering;\n\nuse crate::client::ConnectivityState;\nuse crate::client::load_balancing::ChannelController;\nuse crate::client::load_balancing::FailingPicker;\nuse crate::client::load_balancing::GLOBAL_LB_REGISTRY;\nuse crate::client::load_balancing::LbConfig;\nuse crate::client::load_balancing::LbPolicy;\nuse crate::client::load_balancing::LbPolicyBuilder;\nuse crate::client::load_balancing::LbPolicyOptions;\nuse crate::client::load_balancing::LbState;\nuse crate::client::load_balancing::PickResult;\nuse crate::client::load_balancing::Picker;\nuse crate::client::load_balancing::Subchannel;\nuse crate::client::load_balancing::SubchannelState;\nuse crate::client::load_balancing::child_manager::ChildManager;\nuse crate::client::load_balancing::child_manager::ChildUpdate;\nuse crate::client::load_balancing::pick_first;\nuse crate::client::name_resolution::Endpoint;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::core::RequestHeaders;\n\npub(crate) static POLICY_NAME: &str = \"round_robin\";\nstatic START: Once = Once::new();\n\n#[derive(Debug)]\nstruct RoundRobinBuilder {}\n\nimpl LbPolicyBuilder for RoundRobinBuilder {\n    fn build(&self, options: LbPolicyOptions) -> Box<dyn LbPolicy> {\n        let child_manager = ChildManager::new(options.runtime, options.work_scheduler);\n        Box::new(RoundRobinPolicy::new(\n            child_manager,\n            GLOBAL_LB_REGISTRY\n                .get_policy(pick_first::POLICY_NAME)\n                .unwrap(),\n        ))\n    }\n\n    fn name(&self) -> &'static str {\n        POLICY_NAME\n    }\n}\n\n#[derive(Debug)]\nstruct RoundRobinPolicy {\n    child_manager: ChildManager<Endpoint>,\n    pick_first_builder: Arc<dyn LbPolicyBuilder>,\n}\n\nimpl RoundRobinPolicy {\n    fn new(\n        child_manager: ChildManager<Endpoint>,\n        pick_first_builder: Arc<dyn LbPolicyBuilder>,\n    ) -> Self {\n        Self {\n            child_manager,\n            pick_first_builder,\n        }\n    }\n\n    // Sets the policy's state to TRANSIENT_FAILURE with a picker returning the\n    // error string provided, then requests re-resolution from the channel.\n    fn move_to_transient_failure(\n        &mut self,\n        error: String,\n        channel_controller: &mut dyn ChannelController,\n    ) {\n        channel_controller.update_picker(LbState {\n            connectivity_state: ConnectivityState::TransientFailure,\n            picker: Arc::new(FailingPicker { error }),\n        });\n        channel_controller.request_resolution();\n    }\n\n    // Sends an aggregate picker based on states of children.\n    //\n    // The state is determined according to normal state aggregation rules, and\n    // the picker round-robins between all children in that state.\n    fn update_picker(&mut self, channel_controller: &mut dyn ChannelController) {\n        if !self.child_manager.child_updated() {\n            return;\n        }\n        let aggregate_state = self.child_manager.aggregate_states();\n        let pickers = self\n            .child_manager\n            .children()\n            .filter(|cs| cs.state.connectivity_state == aggregate_state)\n            .map(|cs| cs.state.picker.clone())\n            .collect();\n        let picker_update = LbState {\n            connectivity_state: aggregate_state,\n            picker: Arc::new(RoundRobinPicker::new(pickers)),\n        };\n        channel_controller.update_picker(picker_update);\n    }\n\n    // Responds to an incoming ResolverUpdate containing an Err in endpoints by\n    // forwarding it to all children unconditionally.  Updates the picker as\n    // needed.\n    fn handle_resolver_error(\n        &mut self,\n        resolver_update: ResolverUpdate,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        let err = format!(\n            \"Received error from name resolver: {}\",\n            resolver_update.endpoints.as_ref().unwrap_err()\n        );\n        if self.child_manager.children().next().is_none() {\n            // We had no children so we must produce an erroring picker.\n            self.move_to_transient_failure(err.clone(), channel_controller);\n            return Err(err.into());\n        }\n        // Forward the error to each child, ignoring their responses.\n        let _ = self\n            .child_manager\n            .resolver_update(resolver_update, None, channel_controller);\n        self.update_picker(channel_controller);\n        Err(err.into())\n    }\n}\n\nimpl LbPolicy for RoundRobinPolicy {\n    fn resolver_update(\n        &mut self,\n        update: ResolverUpdate,\n        config: Option<&LbConfig>,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        if update.endpoints.is_err() {\n            return self.handle_resolver_error(update, channel_controller);\n        }\n\n        // Shard the update by endpoint.\n        let updates = update.endpoints.as_ref().unwrap().iter().map(|e| {\n            let update = ResolverUpdate {\n                attributes: crate::attributes::Attributes::default(),\n                endpoints: Ok(vec![e.clone()]),\n                service_config: update.service_config.clone(),\n                resolution_note: None,\n            };\n            ChildUpdate {\n                child_identifier: e.clone(),\n                child_policy_builder: self.pick_first_builder.clone(),\n                child_update: Some((update, config.cloned())),\n            }\n        });\n        self.child_manager\n            .update(updates, channel_controller)\n            .unwrap();\n\n        if self.child_manager.children().next().is_none() {\n            // There are no children remaining, so report this error and produce\n            // an erroring picker.\n            let err = \"Received empty address list from the name resolver\";\n            self.move_to_transient_failure(err.into(), channel_controller);\n            return Err(err.into());\n        }\n\n        self.update_picker(channel_controller);\n        Ok(())\n    }\n\n    fn subchannel_update(\n        &mut self,\n        subchannel: Arc<dyn Subchannel>,\n        state: &SubchannelState,\n        channel_controller: &mut dyn ChannelController,\n    ) {\n        self.child_manager\n            .subchannel_update(subchannel, state, channel_controller);\n        self.update_picker(channel_controller);\n    }\n\n    fn work(&mut self, channel_controller: &mut dyn ChannelController) {\n        self.child_manager.work(channel_controller);\n        self.update_picker(channel_controller);\n    }\n\n    fn exit_idle(&mut self, channel_controller: &mut dyn ChannelController) {\n        self.child_manager.exit_idle(channel_controller);\n        self.update_picker(channel_controller);\n    }\n}\n\n/// Register round robin as a LbPolicy.\npub(crate) fn reg() {\n    START.call_once(|| {\n        GLOBAL_LB_REGISTRY.add_builder(RoundRobinBuilder {});\n    });\n}\n\n#[derive(Debug)]\nstruct RoundRobinPicker {\n    pickers: Vec<Arc<dyn Picker>>,\n    next: AtomicUsize,\n}\n\nimpl RoundRobinPicker {\n    fn new(pickers: Vec<Arc<dyn Picker>>) -> Self {\n        let random_index: usize = rand::random_range(..pickers.len());\n        Self {\n            pickers,\n            next: AtomicUsize::new(random_index),\n        }\n    }\n}\n\nimpl Picker for RoundRobinPicker {\n    fn pick(&self, request_headers: &RequestHeaders) -> PickResult {\n        let len = self.pickers.len();\n        let idx = self.next.fetch_add(1, Ordering::Relaxed) % len;\n        self.pickers[idx].pick(request_headers)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use crate::client::ConnectivityState;\n    use crate::client::load_balancing::ChannelController;\n    use crate::client::load_balancing::FailingPicker;\n    use crate::client::load_balancing::GLOBAL_LB_REGISTRY;\n    use crate::client::load_balancing::LbPolicy;\n    use crate::client::load_balancing::LbState;\n    use crate::client::load_balancing::Pick;\n    use crate::client::load_balancing::PickResult;\n    use crate::client::load_balancing::Picker;\n    use crate::client::load_balancing::QueuingPicker;\n    use crate::client::load_balancing::Subchannel;\n    use crate::client::load_balancing::SubchannelState;\n    use crate::client::load_balancing::child_manager::ChildManager;\n    use crate::client::load_balancing::pick_first;\n    use crate::client::load_balancing::round_robin::RoundRobinPolicy;\n    use crate::client::load_balancing::round_robin::{self};\n    use crate::client::load_balancing::test_utils::StubPolicyData;\n    use crate::client::load_balancing::test_utils::StubPolicyFuncs;\n    use crate::client::load_balancing::test_utils::TestChannelController;\n    use crate::client::load_balancing::test_utils::TestEvent;\n    use crate::client::load_balancing::test_utils::TestWorkScheduler;\n    use crate::client::load_balancing::test_utils::{self};\n    use crate::client::name_resolution::Address;\n    use crate::client::name_resolution::Endpoint;\n    use crate::client::name_resolution::ResolverUpdate;\n    use crate::core::RequestHeaders;\n    use crate::rt::default_runtime;\n    use std::collections::HashSet;\n    use std::panic;\n    use std::sync::Arc;\n    use tokio::sync::mpsc;\n    use tonic::metadata::MetadataMap;\n\n    const DEFAULT_TEST_SHORT_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(100);\n\n    // Sets up the test environment.\n    //\n    // Performs the following:\n    // 1. Creates a work scheduler.\n    // 2. Creates a fake channel that acts as a channel controller.\n    // 3. Creates an StubPolicyBuilder with StubFuncs and the name of the test\n    //    passed in.\n    // 4. Create a Round Robin policy with the StubPolicyBuilder.\n    //\n    // Returns the following:\n    // 1. A receiver for events initiated by the LB policy (like creating a new\n    //    subchannel, sending a new picker etc).\n    // 2. The Round Robin to send resolver and subchannel updates from the test.\n    // 3. The controller to pass to the LB policy as part of the updates.\n    fn setup(\n        test_name: &'static str,\n    ) -> (\n        mpsc::UnboundedReceiver<TestEvent>,\n        impl LbPolicy,\n        Box<dyn ChannelController>,\n    ) {\n        pick_first::reg();\n        round_robin::reg();\n        test_utils::reg_stub_policy(test_name, create_funcs_for_roundrobin_tests());\n\n        let (tx_events, rx_events) = mpsc::unbounded_channel();\n        let work_scheduler = Arc::new(TestWorkScheduler {\n            tx_events: tx_events.clone(),\n        });\n        let child_manager = ChildManager::new(default_runtime(), work_scheduler);\n        let tcc = Box::new(TestChannelController { tx_events });\n        let child_policy_builder = GLOBAL_LB_REGISTRY.get_policy(test_name).unwrap();\n        let lb_policy = RoundRobinPolicy::new(child_manager, child_policy_builder);\n        (rx_events, lb_policy, tcc)\n    }\n\n    struct TestSubchannelList {\n        subchannels: Vec<Arc<dyn Subchannel>>,\n    }\n\n    impl TestSubchannelList {\n        fn new(addresses: &[Address], channel_controller: &mut dyn ChannelController) -> Self {\n            TestSubchannelList {\n                subchannels: addresses\n                    .iter()\n                    .map(|a| channel_controller.new_subchannel(a))\n                    .collect(),\n            }\n        }\n\n        fn contains(&self, sc: &Arc<dyn Subchannel>) -> bool {\n            self.subchannels.contains(sc)\n        }\n    }\n\n    fn create_endpoints(num_endpoints: usize, num_addresses: usize) -> Vec<Endpoint> {\n        let mut endpoints = Vec::with_capacity(num_endpoints);\n        for i in 0..num_endpoints {\n            let mut addresses: Vec<Address> = Vec::with_capacity(num_addresses);\n            for j in 0..num_addresses {\n                addresses.push(Address {\n                    address: format!(\"{}.{}.{}.{}:{}\", i + 1, i + 1, i + 1, i + 1, j).into(),\n                    ..Default::default()\n                });\n            }\n            endpoints.push(Endpoint {\n                addresses,\n                ..Default::default()\n            })\n        }\n        endpoints\n    }\n\n    // Sends a resolver update to the LB policy with the specified endpoint.\n    fn send_resolver_update_to_policy(\n        lb_policy: &mut impl LbPolicy,\n        endpoints: Vec<Endpoint>,\n        tcc: &mut dyn ChannelController,\n    ) {\n        let update = ResolverUpdate {\n            endpoints: Ok(endpoints),\n            ..Default::default()\n        };\n        let _ = lb_policy.resolver_update(update, None, tcc);\n    }\n\n    fn send_resolver_error_to_policy(\n        lb_policy: &mut impl LbPolicy,\n        err: String,\n        tcc: &mut dyn ChannelController,\n    ) {\n        let update = ResolverUpdate {\n            endpoints: Err(err),\n            ..Default::default()\n        };\n        let _ = lb_policy.resolver_update(update, None, tcc);\n    }\n\n    fn move_subchannel_to_state(\n        lb_policy: &mut impl LbPolicy,\n        subchannel: Arc<dyn Subchannel>,\n        state: ConnectivityState,\n        tcc: &mut dyn ChannelController,\n    ) {\n        lb_policy.subchannel_update(\n            subchannel,\n            &SubchannelState {\n                connectivity_state: state,\n                ..Default::default()\n            },\n            tcc,\n        );\n    }\n\n    fn move_subchannel_to_transient_failure(\n        lb_policy: &mut impl LbPolicy,\n        subchannel: Arc<dyn Subchannel>,\n        err: &str,\n        tcc: &mut dyn ChannelController,\n    ) {\n        lb_policy.subchannel_update(\n            subchannel,\n            &SubchannelState {\n                connectivity_state: ConnectivityState::TransientFailure,\n                last_connection_error: Some(Arc::from(Box::from(err.to_owned()))),\n            },\n            tcc,\n        );\n    }\n\n    #[derive(Debug)]\n    struct OneSubchannelPicker {\n        sc: Arc<dyn Subchannel>,\n    }\n\n    impl Picker for OneSubchannelPicker {\n        fn pick(&self, _: &RequestHeaders) -> PickResult {\n            PickResult::Pick(Pick {\n                subchannel: self.sc.clone(),\n                on_complete: None,\n                metadata: MetadataMap::new(),\n            })\n        }\n    }\n\n    fn addresses_from_endpoints(endpoints: &[Endpoint]) -> Vec<Address> {\n        let mut addresses: Vec<Address> = endpoints\n            .iter()\n            .flat_map(|ep| ep.addresses.clone())\n            .collect();\n        let mut uniques = HashSet::new();\n        addresses.retain(|e| uniques.insert(e.clone()));\n        addresses\n    }\n\n    struct PickFirstState {\n        subchannel_list: Option<TestSubchannelList>,\n        selected_subchannel: Option<Arc<dyn Subchannel>>,\n        addresses: Vec<Address>,\n        connectivity_state: ConnectivityState,\n    }\n\n    // TODO: Replace with Pick First child once merged.\n    // Defines the functions resolver_update and subchannel_update to test round\n    // robin. This is a simplified version of PickFirst. It just creates a\n    // subchannel and then sends the appropriate picker update.\n    fn create_funcs_for_roundrobin_tests() -> StubPolicyFuncs {\n        StubPolicyFuncs {\n            // Closure for resolver_update. It creates a subchannel for the\n            // endpoint it receives and stores which endpoint it received and\n            // which subchannel this child created in the data field.\n            resolver_update: Some(Arc::new(\n                |data: &mut StubPolicyData, update: ResolverUpdate, _, channel_controller| {\n                    let state = data\n                        .test_data\n                        .get_or_insert_with(|| {\n                            Box::new(PickFirstState {\n                                subchannel_list: None,\n                                selected_subchannel: None,\n                                addresses: vec![],\n                                connectivity_state: ConnectivityState::Connecting,\n                            })\n                        })\n                        .downcast_mut::<PickFirstState>()\n                        .unwrap();\n                    if let Err(error) = update.endpoints {\n                        if state.addresses.is_empty()\n                            || state.connectivity_state == ConnectivityState::TransientFailure\n                        {\n                            channel_controller.update_picker(LbState {\n                                connectivity_state: ConnectivityState::TransientFailure,\n                                picker: Arc::new(FailingPicker {\n                                    error: error.to_string(),\n                                }),\n                            });\n                            state.connectivity_state = ConnectivityState::TransientFailure;\n                            channel_controller.request_resolution();\n                        }\n                        return Ok(());\n                    };\n                    let endpoints = update.endpoints.unwrap();\n                    let new_addresses = addresses_from_endpoints(&endpoints);\n                    if new_addresses.is_empty() {\n                        channel_controller.update_picker(LbState {\n                            connectivity_state: ConnectivityState::TransientFailure,\n                            picker: Arc::new(FailingPicker {\n                                error: \"Received empty address list from the name resolver\"\n                                    .to_string(),\n                            }),\n                        });\n                        state.connectivity_state = ConnectivityState::TransientFailure;\n                        channel_controller.request_resolution();\n                        return Err(\"Received empty address list from the name resolver\".into());\n                    }\n\n                    if state.connectivity_state != ConnectivityState::Idle {\n                        state.subchannel_list =\n                            Some(TestSubchannelList::new(&new_addresses, channel_controller));\n                    }\n                    state.addresses = new_addresses;\n                    Ok(())\n                },\n            )),\n            // Closure for subchannel_update. Verify that the subchannel being\n            // updated is the same one that this child policy created in\n            // resolver_update. It then sends a picker of the same state that\n            // was passed to it.\n            subchannel_update: Some(Arc::new(\n                |data: &mut StubPolicyData, subchannel, state, channel_controller| {\n                    // Retrieve the specific TestState from the generic test_data field.\n                    // This downcasts the `Any` trait object\n                    let test_data = data.test_data.as_mut().unwrap(); // ? ignore?\n                    let test_state = test_data.downcast_mut::<PickFirstState>().unwrap();\n                    let scl = &mut test_state.subchannel_list.as_ref().unwrap();\n                    assert!(\n                        scl.contains(&subchannel),\n                        \"subchannel_update received an update for a subchannel it does not own.\"\n                    );\n                    test_state.connectivity_state = state.connectivity_state;\n                    match state.connectivity_state {\n                        ConnectivityState::Ready => {\n                            channel_controller.update_picker(LbState {\n                                connectivity_state: state.connectivity_state,\n                                picker: Arc::new(OneSubchannelPicker { sc: subchannel }),\n                            });\n                        }\n                        ConnectivityState::Idle => {}\n                        ConnectivityState::Connecting => {\n                            channel_controller.update_picker(LbState {\n                                connectivity_state: state.connectivity_state,\n                                picker: Arc::new(QueuingPicker {}),\n                            });\n                        }\n                        ConnectivityState::TransientFailure => {\n                            channel_controller.update_picker(LbState {\n                                connectivity_state: state.connectivity_state,\n                                picker: Arc::new(FailingPicker {\n                                    error: state\n                                        .last_connection_error\n                                        .as_ref()\n                                        .unwrap()\n                                        .to_string(),\n                                }),\n                            });\n                        }\n                    }\n                },\n            )),\n            work: None,\n        }\n    }\n\n    // Creates a new endpoint with the specified number of addresses.\n    fn create_endpoint(num_addresses: usize) -> Endpoint {\n        let mut addresses = Vec::with_capacity(num_addresses);\n        for i in 0..num_addresses {\n            addresses.push(Address {\n                address: format!(\"{}.{}.{}.{}:{}\", i, i, i, i, i).into(),\n                ..Default::default()\n            });\n        }\n        Endpoint {\n            addresses,\n            ..Default::default()\n        }\n    }\n\n    // Verifies that the expected number of subchannels is created. Returns the\n    // subchannels created.\n    async fn verify_subchannel_creation(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n        number_of_subchannels: usize,\n    ) -> Vec<Arc<dyn Subchannel>> {\n        let mut subchannels = Vec::new();\n        for _ in 0..number_of_subchannels {\n            match rx_events.recv().await.unwrap() {\n                TestEvent::NewSubchannel(sc) => {\n                    subchannels.push(sc);\n                }\n                other => panic!(\"unexpected event {:?}\", other),\n            };\n        }\n        subchannels\n    }\n\n    // Verifies that the channel moves to CONNECTING state with a queuing picker.\n    //\n    // Returns the picker for tests to make more picks, if required.\n    async fn verify_connecting_picker(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n    ) -> Arc<dyn Picker> {\n        println!(\"verify connecting picker\");\n        match rx_events.recv().await.unwrap() {\n            TestEvent::UpdatePicker(update) => {\n                println!(\"connectivity state is {}\", update.connectivity_state);\n                assert!(update.connectivity_state == ConnectivityState::Connecting);\n                let req = test_utils::new_request_headers();\n                assert!(update.picker.pick(&req) == PickResult::Queue);\n                update.picker\n            }\n            other => panic!(\"unexpected event {:?}\", other),\n        }\n    }\n\n    // Verifies that the channel moves to READY state with a picker that returns\n    // the given subchannel.\n    //\n    // Returns the picker for tests to make more picks, if required.\n    async fn verify_ready_picker(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n        subchannel: Arc<dyn Subchannel>,\n    ) -> Arc<dyn Picker> {\n        println!(\"verify ready picker\");\n        match rx_events.recv().await.unwrap() {\n            TestEvent::UpdatePicker(update) => {\n                println!(\n                    \"connectivity state for ready picker is {}\",\n                    update.connectivity_state\n                );\n                assert!(update.connectivity_state == ConnectivityState::Ready);\n                let req = test_utils::new_request_headers();\n                match update.picker.pick(&req) {\n                    PickResult::Pick(pick) => {\n                        println!(\"selected subchannel is {}\", pick.subchannel);\n                        println!(\"should've been selected subchannel is {}\", subchannel);\n                        assert!(pick.subchannel == subchannel.clone());\n                        update.picker.clone()\n                    }\n                    other => panic!(\"unexpected pick result {}\", other),\n                }\n            }\n            other => panic!(\"unexpected event {:?}\", other),\n        }\n    }\n\n    // Returns the picker for when there are multiple pickers in the ready\n    // picker.\n    async fn verify_roundrobin_ready_picker(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n    ) -> Arc<dyn Picker> {\n        println!(\"verify ready picker\");\n        match rx_events.recv().await.unwrap() {\n            TestEvent::UpdatePicker(update) => {\n                println!(\n                    \"connectivity state for ready picker is {}\",\n                    update.connectivity_state\n                );\n                assert!(update.connectivity_state == ConnectivityState::Ready);\n                let req = test_utils::new_request_headers();\n                match update.picker.pick(&req) {\n                    PickResult::Pick(pick) => update.picker.clone(),\n                    other => panic!(\"unexpected pick result {}\", other),\n                }\n            }\n            other => panic!(\"unexpected event {:?}\", other),\n        }\n    }\n\n    // Verifies that the channel moves to TRANSIENT_FAILURE state with a picker\n    // that returns an error with the given message. The error code should be\n    // UNAVAILABLE..\n    //\n    // Returns the picker for tests to make more picks, if required.\n    async fn verify_transient_failure_picker(\n        rx_events: &mut mpsc::UnboundedReceiver<TestEvent>,\n        want_error: String,\n    ) -> Arc<dyn Picker> {\n        (match rx_events.recv().await.unwrap() {\n            TestEvent::UpdatePicker(update) => {\n                assert!(update.connectivity_state == ConnectivityState::TransientFailure);\n                let req = test_utils::new_request_headers();\n                match update.picker.pick(&req) {\n                    PickResult::Fail(status) => {\n                        assert!(status.code() == tonic::Code::Unavailable);\n                        dbg!(status.message());\n                        dbg!(&want_error);\n                        assert!(status.message().contains(&want_error));\n                        update.picker.clone()\n                    }\n                    other => panic!(\"unexpected pick result {}\", other),\n                }\n            }\n            other => panic!(\"unexpected event {:?}\", other),\n        }) as _\n    }\n\n    // Verifies that the LB policy requests re-resolution.\n    async fn verify_resolution_request(rx_events: &mut mpsc::UnboundedReceiver<TestEvent>) {\n        println!(\"verifying resolution request\");\n        match rx_events.recv().await.unwrap() {\n            TestEvent::RequestResolution => {}\n            other => panic!(\"unexpected event {:?}\", other),\n        };\n    }\n\n    async fn verify_no_activity(rx_events: &mut mpsc::UnboundedReceiver<TestEvent>) {\n        tokio::select! {\n            _ = tokio::time::sleep(DEFAULT_TEST_SHORT_TIMEOUT) => {}\n            event = rx_events.recv() => {\n                panic!(\"unexpected event {:?}\", event.unwrap());\n            }\n        }\n    }\n\n    // Tests the scenario where the resolver returns an error before a valid\n    // update. The LB policy should move to TRANSIENT_FAILURE state with a\n    // failing picker.\n    #[tokio::test]\n    async fn roundrobin_resolver_error_before_a_valid_update() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_resolver_error_before_a_valid_update\");\n        let tcc = tcc.as_mut();\n        let resolver_error = String::from(\"resolver error\");\n        send_resolver_error_to_policy(&mut lb_policy, resolver_error.clone(), tcc);\n        verify_transient_failure_picker(&mut rx_events, resolver_error).await;\n    }\n\n    // Tests the scenario where the resolver returns an error after a valid update\n    // and the LB policy has moved to READY. The LB policy should ignore the error\n    // and continue using the previously received update.\n    #[tokio::test]\n    async fn roundrobin_resolver_error_after_a_valid_update_in_ready() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_resolver_error_after_a_valid_update_in_ready\");\n        let tcc = tcc.as_mut();\n        let endpoint = create_endpoint(1);\n        send_resolver_update_to_policy(&mut lb_policy, vec![endpoint], tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 1).await;\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        let picker = verify_ready_picker(&mut rx_events, subchannels[0].clone()).await;\n        let resolver_error = String::from(\"resolver error\");\n        send_resolver_error_to_policy(&mut lb_policy, resolver_error.clone(), tcc);\n        verify_no_activity(&mut rx_events).await;\n\n        let req = test_utils::new_request_headers();\n        match picker.pick(&req) {\n            PickResult::Pick(pick) => {\n                assert!(pick.subchannel == subchannels[0].clone());\n            }\n            other => panic!(\"unexpected pick result {}\", other),\n        }\n    }\n\n    // Tests the scenario where the resolver returns an error after a valid update\n    // and the LB policy is still trying to connect. The LB policy should ignore the\n    // error and continue using the previously received update.\n    #[tokio::test]\n    async fn roundrobin_resolver_error_after_a_valid_update_in_connecting() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_resolver_error_after_a_valid_update_in_connecting\");\n        let tcc = tcc.as_mut();\n\n        let endpoint = create_endpoint(1);\n        send_resolver_update_to_policy(&mut lb_policy, vec![endpoint], tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 1).await;\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        let picker = verify_connecting_picker(&mut rx_events).await;\n\n        let resolver_error = String::from(\"resolver error\");\n\n        send_resolver_error_to_policy(&mut lb_policy, resolver_error, tcc);\n\n        verify_no_activity(&mut rx_events).await;\n\n        let req = test_utils::new_request_headers();\n        match picker.pick(&req) {\n            PickResult::Queue => {}\n            other => panic!(\"unexpected pick result {}\", other),\n        }\n    }\n\n    // Tests the scenario where the resolver returns an error after a valid\n    // update and the LB policy has moved to TRANSIENT_FAILURE after attempting\n    // to connect to all addresses. The LB policy should send a new picker that\n    // returns the error from the resolver.\n    #[tokio::test]\n    async fn roundrobin_resolver_error_after_a_valid_update_in_tf() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_resolver_error_after_a_valid_update_in_tf\");\n        let tcc = tcc.as_mut();\n        let endpoint = create_endpoint(1);\n        send_resolver_update_to_policy(&mut lb_policy, vec![endpoint], tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 1).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        let connection_error = String::from(\"test connection error\");\n        move_subchannel_to_transient_failure(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            &connection_error,\n            tcc,\n        );\n        verify_transient_failure_picker(&mut rx_events, connection_error).await;\n        let resolver_error = String::from(\"resolver error\");\n        send_resolver_error_to_policy(&mut lb_policy, resolver_error.clone(), tcc);\n        verify_resolution_request(&mut rx_events).await;\n        verify_transient_failure_picker(&mut rx_events, resolver_error).await;\n    }\n\n    // Round Robin should round robin across endpoints.\n    #[tokio::test]\n    async fn roundrobin_picks_are_round_robin() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_picks_are_round_robin\");\n        let tcc = tcc.as_mut();\n        let endpoints = create_endpoints(2, 1);\n        send_resolver_update_to_policy(&mut lb_policy, endpoints, tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        verify_ready_picker(&mut rx_events, subchannels[0].clone()).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[1].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        let picker = verify_roundrobin_ready_picker(&mut rx_events).await;\n        let req = test_utils::new_request_headers();\n        let mut picked = Vec::new();\n        for _ in 0..4 {\n            match picker.pick(&req) {\n                PickResult::Pick(pick) => {\n                    println!(\"picked subchannel is {}\", pick.subchannel);\n                    picked.push(pick.subchannel.clone())\n                }\n                other => panic!(\"unexpected pick result {}\", other),\n            }\n        }\n        assert!(\n            picked[0] != picked[1].clone(),\n            \"Should alternate between subchannels\"\n        );\n        assert_eq!(&picked[0], &picked[2]);\n        assert_eq!(&picked[1], &picked[3]);\n        assert!(picked.contains(&subchannels[0]));\n        assert!(picked.contains(&subchannels[1]));\n    }\n\n    // If round robin receives no endpoints in a resolver update,\n    // it should go into transient failure.\n    #[tokio::test]\n    async fn roundrobin_endpoints_removed() {\n        let (mut rx_events, mut lb_policy, mut tcc) = setup(\"stub-roundrobin_addresses_removed\");\n        let tcc = tcc.as_mut();\n\n        let endpoints = create_endpoints(2, 1);\n        send_resolver_update_to_policy(&mut lb_policy, endpoints, tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![]),\n            ..Default::default()\n        };\n        let _ = lb_policy.resolver_update(update, None, tcc);\n        let want_error = \"Received empty address list from the name resolver\";\n        verify_transient_failure_picker(&mut rx_events, want_error.to_string()).await;\n        verify_resolution_request(&mut rx_events).await;\n    }\n\n    // Round robin should only round robin across children that are ready.\n    // If a child leaves the ready state, Round Robin should only\n    // pick from the children that are still Ready.\n    #[tokio::test]\n    async fn roundrobin_one_endpoint_down() {\n        let (mut rx_events, mut lb_policy, mut tcc) = setup(\"stub-roundrobin_one_endpoint_down\");\n        let tcc = tcc.as_mut();\n        let endpoints = create_endpoints(2, 1);\n        send_resolver_update_to_policy(&mut lb_policy, endpoints, tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        let picker = verify_ready_picker(&mut rx_events, subchannels[0].clone()).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[1].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        let picker = verify_roundrobin_ready_picker(&mut rx_events).await;\n        let req = test_utils::new_request_headers();\n        let mut picked = Vec::new();\n        for _ in 0..4 {\n            match picker.pick(&req) {\n                PickResult::Pick(pick) => {\n                    println!(\"picked subchannel is {}\", pick.subchannel);\n                    picked.push(pick.subchannel.clone())\n                }\n                other => panic!(\"unexpected pick result {}\", other),\n            }\n        }\n        assert!(\n            picked[0] != picked[1].clone(),\n            \"Should alternate between subchannels\"\n        );\n        assert_eq!(&picked[0], &picked[2]);\n        assert_eq!(&picked[1], &picked[3]);\n\n        assert!(picked.contains(&subchannels[0]));\n        assert!(picked.contains(&subchannels[1]));\n        let subchannel_being_removed = subchannels[1].clone();\n        let error = \"endpoint down\";\n        move_subchannel_to_transient_failure(&mut lb_policy, subchannels[1].clone(), error, tcc);\n\n        let new_picker = verify_roundrobin_ready_picker(&mut rx_events).await;\n\n        let req = test_utils::new_request_headers();\n        let mut picked = Vec::new();\n        for _ in 0..4 {\n            match new_picker.pick(&req) {\n                PickResult::Pick(pick) => {\n                    println!(\"picked subchannel is {}\", pick.subchannel);\n                    picked.push(pick.subchannel.clone())\n                }\n                other => panic!(\"unexpected pick result {}\", other),\n            }\n        }\n\n        assert_eq!(&picked[0], &picked[2]);\n        assert_eq!(&picked[1], &picked[3]);\n        assert!(picked.contains(&subchannels[0]));\n        assert!(!picked.contains(&subchannel_being_removed));\n    }\n\n    // If Round Robin receives a resolver update that removes an endpoint and\n    // adds a new endpoint from a previous update, that endpoint's subchannels\n    // should not be a part of its picks anymore and should be removed. It should\n    // then roundrobin across the endpoints it still has and the new one.\n    #[tokio::test]\n    async fn roundrobin_pick_after_resolved_updated_hosts() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_pick_after_resolved_updated_hosts\");\n        let tcc = tcc.as_mut();\n\n        // Two initial endpoints: subchannel_one, subchannel_two\n        let addr_one = Address {\n            address: \"subchannel_one\".to_string().into(),\n            ..Default::default()\n        };\n        let addr_two = Address {\n            address: \"subchannel_two\".to_string().into(),\n            ..Default::default()\n        };\n        let endpoint_one = Endpoint {\n            addresses: vec![addr_one],\n            ..Default::default()\n        };\n        let endpoint_two = Endpoint {\n            addresses: vec![addr_two],\n            ..Default::default()\n        };\n\n        send_resolver_update_to_policy(\n            &mut lb_policy,\n            vec![endpoint_one, endpoint_two.clone()],\n            tcc,\n        );\n\n        // Start with two subchannels created\n        let all_subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n        let subchannel_one = all_subchannels\n            .iter()\n            .find(|sc| sc.address().address == \"subchannel_one\".to_string().into())\n            .unwrap();\n        let subchannel_two = all_subchannels\n            .iter()\n            .find(|sc| sc.address().address == \"subchannel_two\".to_string().into())\n            .unwrap();\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannel_one.clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannel_two.clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannel_one.clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        verify_ready_picker(&mut rx_events, subchannel_one.clone()).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannel_two.clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        let picker = verify_roundrobin_ready_picker(&mut rx_events).await;\n\n        let req = test_utils::new_request_headers();\n        let mut picked = Vec::new();\n        for _ in 0..4 {\n            match picker.pick(&req) {\n                PickResult::Pick(pick) => picked.push(pick.subchannel.clone()),\n                other => panic!(\"unexpected pick result {}\", other),\n            }\n        }\n        assert!(picked.contains(subchannel_one));\n        assert!(picked.contains(subchannel_two));\n\n        // Resolver update removes subchannel_one and adds \"new\"\n        let new_addr = Address {\n            address: \"new\".to_string().into(),\n            ..Default::default()\n        };\n        let new_endpoint = Endpoint {\n            addresses: vec![new_addr],\n            ..Default::default()\n        };\n\n        send_resolver_update_to_policy(&mut lb_policy, vec![endpoint_two, new_endpoint], tcc);\n\n        let new_subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n        let new_sc = new_subchannels\n            .iter()\n            .find(|sc| sc.address().address == \"new\".to_string().into())\n            .unwrap();\n        let old_sc = new_subchannels\n            .iter()\n            .find(|sc| sc.address().address == \"subchannel_two\".to_string().into())\n            .unwrap();\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            old_sc.clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        let _ = verify_roundrobin_ready_picker(&mut rx_events).await;\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            new_sc.clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        let _ = verify_roundrobin_ready_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            new_sc.clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        let new_picker = verify_roundrobin_ready_picker(&mut rx_events).await;\n\n        let req = test_utils::new_request_headers();\n        let mut picked = Vec::new();\n        for _ in 0..4 {\n            match new_picker.pick(&req) {\n                PickResult::Pick(pick) => picked.push(pick.subchannel.clone()),\n                other => panic!(\"unexpected pick result {}\", other),\n            }\n        }\n        assert!(picked.contains(old_sc));\n        assert!(picked.contains(new_sc));\n        assert!(!picked.contains(subchannel_one));\n    }\n\n    // Round robin should stay in transient failure until a child reports ready\n    #[tokio::test]\n    async fn roundrobin_stay_transient_failure_until_ready() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_stay_transient_failure_until_ready\");\n        let tcc = tcc.as_mut();\n        let endpoints = create_endpoints(2, 1);\n        send_resolver_update_to_policy(&mut lb_policy, endpoints, tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[1].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        let first_error = String::from(\"test connection error 1\");\n        move_subchannel_to_transient_failure(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            &first_error,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_transient_failure(\n            &mut lb_policy,\n            subchannels[1].clone(),\n            &first_error,\n            tcc,\n        );\n        verify_transient_failure_picker(&mut rx_events, first_error).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        verify_ready_picker(&mut rx_events, subchannels[0].clone()).await;\n    }\n\n    // Tests the scenario where the resolver returns an update with no endpoints\n    // (before sending any valid update). The LB policy should move to\n    // TRANSIENT_FAILURE state with a failing picker.\n    #[tokio::test]\n    async fn roundrobin_zero_endpoints_from_resolver_before_valid_update() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_zero_endpoints_from_resolver_before_valid_update\");\n        let tcc = tcc.as_mut();\n        send_resolver_update_to_policy(&mut lb_policy, vec![], tcc);\n        verify_transient_failure_picker(\n            &mut rx_events,\n            \"Received empty address list from the name resolver\".to_string(),\n        )\n        .await;\n    }\n\n    // Tests the scenario where the resolver returns an update with no endpoints\n    // after sending a valid update (and the LB policy has moved to READY). The LB\n    // policy should move to TRANSIENT_FAILURE state with a failing picker.\n    #[tokio::test]\n    async fn roundrobin_zero_endpoints_from_resolver_after_valid_update() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_zero_endpoints_from_resolver_after_valid_update\");\n        let tcc = tcc.as_mut();\n\n        let endpoint = create_endpoint(1);\n        send_resolver_update_to_policy(&mut lb_policy, vec![endpoint], tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 1).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        verify_ready_picker(&mut rx_events, subchannels[0].clone()).await;\n        let update = ResolverUpdate {\n            endpoints: Ok(vec![]),\n            ..Default::default()\n        };\n        assert!(lb_policy.resolver_update(update, None, tcc).is_err());\n        verify_transient_failure_picker(\n            &mut rx_events,\n            \"Received empty address list from the name resolver\".to_string(),\n        )\n        .await;\n        verify_resolution_request(&mut rx_events).await;\n    }\n\n    // Tests the scenario where the resolver returns an update with multiple\n    // address. The LB policy should create subchannels for all address, and attempt\n    // to connect to them in order, until a connection succeeds, at which point it\n    // should move to READY state with a picker that returns that subchannel.\n    #[tokio::test]\n    async fn roundrobin_with_multiple_backends_first_backend_is_ready() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_with_multiple_backends_first_backend_is_ready\");\n        let tcc = tcc.as_mut();\n\n        let endpoint = create_endpoints(2, 1);\n        send_resolver_update_to_policy(&mut lb_policy, endpoint, tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n\n        let picker = verify_ready_picker(&mut rx_events, subchannels[0].clone()).await;\n\n        let req = test_utils::new_request_headers();\n        // First pick determines the only subchannel the picker should yield\n        let first_sc = match picker.pick(&req) {\n            PickResult::Pick(p) => p.subchannel.clone(),\n            other => panic!(\"unexpected pick result {}\", other),\n        };\n\n        for _ in 0..7 {\n            match picker.pick(&req) {\n                PickResult::Pick(p) => {\n                    assert!(\n                        Arc::ptr_eq(&first_sc, &p.subchannel),\n                        \"READY picker should contain exactly one subchannel\"\n                    );\n                }\n                other => panic!(\"unexpected pick result {}\", other),\n            }\n        }\n    }\n\n    // Tests the scenario where the resolver returns an update with multiple\n    // addresses and the LB policy successfully connects to first one and moves to\n    // READY. The resolver then returns an update with a new address list that\n    // contains the address of the currently connected subchannel. The LB policy\n    // should create subchannels for the new addresses, and then see that the\n    // currently connected subchannel is in the new address list. It should then\n    // send a new READY picker that returns the currently connected subchannel.\n    #[tokio::test]\n    async fn roundrobin_resolver_update_contains_currently_ready_subchannel() {\n        let (mut rx_events, mut lb_policy, mut tcc) =\n            setup(\"stub-roundrobin_resolver_update_contains_currently_ready_subchannel\");\n        let tcc = tcc.as_mut();\n\n        let endpoints = create_endpoint(2);\n        send_resolver_update_to_policy(&mut lb_policy, vec![endpoints], tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 2).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Connecting,\n            tcc,\n        );\n        verify_connecting_picker(&mut rx_events).await;\n        move_subchannel_to_state(\n            &mut lb_policy,\n            subchannels[0].clone(),\n            ConnectivityState::Ready,\n            tcc,\n        );\n        verify_ready_picker(&mut rx_events, subchannels[0].clone()).await;\n\n        let mut endpoints = create_endpoint(4);\n        endpoints.addresses.reverse();\n        send_resolver_update_to_policy(&mut lb_policy, vec![endpoints], tcc);\n        let subchannels = verify_subchannel_creation(&mut rx_events, 4).await;\n        lb_policy.subchannel_update(subchannels[0].clone(), &SubchannelState::default(), tcc);\n        lb_policy.subchannel_update(subchannels[1].clone(), &SubchannelState::default(), tcc);\n        lb_policy.subchannel_update(subchannels[2].clone(), &SubchannelState::default(), tcc);\n        lb_policy.subchannel_update(\n            subchannels[3].clone(),\n            &SubchannelState {\n                connectivity_state: ConnectivityState::Ready,\n                ..Default::default()\n            },\n            tcc,\n        );\n        verify_ready_picker(&mut rx_events, subchannels[3].clone()).await;\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/load_balancing/test_utils.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::any::Any;\nuse std::error::Error;\nuse std::fmt::Debug;\nuse std::hash::Hash;\nuse std::sync::Arc;\n\nuse serde::Deserialize;\nuse serde::Serialize;\nuse tokio::sync::Notify;\nuse tokio::sync::mpsc;\n\nuse crate::client::load_balancing::ChannelController;\nuse crate::client::load_balancing::ForwardingSubchannel;\nuse crate::client::load_balancing::LbPolicy;\nuse crate::client::load_balancing::LbPolicyBuilder;\nuse crate::client::load_balancing::LbPolicyOptions;\nuse crate::client::load_balancing::LbState;\nuse crate::client::load_balancing::ParsedJsonLbConfig;\nuse crate::client::load_balancing::Subchannel;\nuse crate::client::load_balancing::SubchannelState;\nuse crate::client::load_balancing::WorkScheduler;\nuse crate::client::name_resolution::Address;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::client::service_config::LbConfig;\nuse crate::core::RequestHeaders;\n\npub(crate) fn new_request_headers() -> RequestHeaders {\n    RequestHeaders::default()\n}\n\n// A test subchannel that forwards connect calls to a channel.\n// This allows tests to verify when a subchannel is asked to connect.\npub(crate) struct TestSubchannel {\n    address: Address,\n    tx_connect: mpsc::UnboundedSender<TestEvent>,\n}\n\nimpl TestSubchannel {\n    pub fn new(address: Address, tx_connect: mpsc::UnboundedSender<TestEvent>) -> Self {\n        Self {\n            address,\n            tx_connect,\n        }\n    }\n}\n\nimpl ForwardingSubchannel for TestSubchannel {\n    fn delegate(&self) -> Arc<dyn Subchannel> {\n        panic!(\"unsupported operation on a test subchannel\");\n    }\n\n    fn address(&self) -> Address {\n        self.address.clone()\n    }\n\n    fn connect(&self) {\n        println!(\"connect called for subchannel {}\", self.address);\n        self.tx_connect\n            .send(TestEvent::Connect(self.address.clone()))\n            .unwrap();\n    }\n}\n\nimpl Hash for TestSubchannel {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.address.hash(state);\n    }\n}\n\nimpl PartialEq for TestSubchannel {\n    fn eq(&self, other: &Self) -> bool {\n        std::ptr::eq(self, other)\n    }\n}\nimpl Eq for TestSubchannel {}\n\npub(crate) enum TestEvent {\n    NewSubchannel(Arc<dyn Subchannel>),\n    UpdatePicker(LbState),\n    RequestResolution,\n    Connect(Address),\n    ScheduleWork,\n}\n\n// TODO(easwars): Remove this and instead derive Debug.\nimpl Debug for TestEvent {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::NewSubchannel(sc) => write!(f, \"NewSubchannel({})\", sc.address()),\n            Self::UpdatePicker(state) => write!(f, \"UpdatePicker({})\", state.connectivity_state),\n            Self::RequestResolution => write!(f, \"RequestResolution\"),\n            Self::Connect(addr) => write!(f, \"Connect({:?})\", addr.address),\n            Self::ScheduleWork => write!(f, \"ScheduleWork\"),\n        }\n    }\n}\n\n/// A test channel controller that forwards calls to a channel.  This allows\n/// tests to verify when a channel controller is asked to create subchannels or\n/// update the picker.\npub(crate) struct TestChannelController {\n    pub(crate) tx_events: mpsc::UnboundedSender<TestEvent>,\n}\n\nimpl ChannelController for TestChannelController {\n    fn new_subchannel(&mut self, address: &Address) -> Arc<dyn Subchannel> {\n        println!(\"new_subchannel called for address {}\", address);\n        let notify = Arc::new(Notify::new());\n        let subchannel: Arc<dyn Subchannel> =\n            Arc::new(TestSubchannel::new(address.clone(), self.tx_events.clone()));\n        self.tx_events\n            .send(TestEvent::NewSubchannel(subchannel.clone()))\n            .unwrap();\n        subchannel\n    }\n    fn update_picker(&mut self, update: LbState) {\n        println!(\"picker_update called with {}\", update.connectivity_state);\n        self.tx_events\n            .send(TestEvent::UpdatePicker(update))\n            .unwrap();\n    }\n    fn request_resolution(&mut self) {\n        self.tx_events.send(TestEvent::RequestResolution).unwrap();\n    }\n}\n\n#[derive(Debug)]\npub(crate) struct TestWorkScheduler {\n    pub(crate) tx_events: mpsc::UnboundedSender<TestEvent>,\n}\n\nimpl WorkScheduler for TestWorkScheduler {\n    fn schedule_work(&self) {\n        self.tx_events.send(TestEvent::ScheduleWork).unwrap();\n    }\n}\n\n// The callback to invoke when resolver_update is invoked on the stub policy.\ntype ResolverUpdateFn = Arc<\n    dyn Fn(\n            &mut StubPolicyData,\n            ResolverUpdate,\n            Option<&LbConfig>,\n            &mut dyn ChannelController,\n        ) -> Result<(), Box<dyn Error + Send + Sync>>\n        + Send\n        + Sync,\n>;\n\n// The callback to invoke when subchannel_update is invoked on the stub policy.\ntype SubchannelUpdateFn = Arc<\n    dyn Fn(&mut StubPolicyData, Arc<dyn Subchannel>, &SubchannelState, &mut dyn ChannelController)\n        + Send\n        + Sync,\n>;\n\ntype WorkFn = Arc<dyn Fn(&mut StubPolicyData, &mut dyn ChannelController) + Send + Sync>;\n\n/// This struct holds `LbPolicy` trait stub functions that tests are expected to\n/// implement.\n#[derive(Clone)]\npub(crate) struct StubPolicyFuncs {\n    pub resolver_update: Option<ResolverUpdateFn>,\n    pub subchannel_update: Option<SubchannelUpdateFn>,\n    pub work: Option<WorkFn>,\n}\n\nimpl Debug for StubPolicyFuncs {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"stub funcs\")\n    }\n}\n\n/// Data holds test data that will be passed all to functions in PolicyFuncs\n#[derive(Debug)]\npub(crate) struct StubPolicyData {\n    pub lb_policy_options: LbPolicyOptions,\n    pub test_data: Option<Box<dyn Any + Send + Sync>>,\n}\n\nimpl StubPolicyData {\n    /// Creates an instance of StubPolicyData.\n    pub fn new(lb_policy_options: LbPolicyOptions) -> Self {\n        Self {\n            test_data: None,\n            lb_policy_options,\n        }\n    }\n}\n\n/// The stub `LbPolicy` that calls the provided functions.\n#[derive(Debug)]\npub(crate) struct StubPolicy {\n    funcs: StubPolicyFuncs,\n    data: StubPolicyData,\n}\n\nimpl LbPolicy for StubPolicy {\n    fn resolver_update(\n        &mut self,\n        update: ResolverUpdate,\n        config: Option<&LbConfig>,\n        channel_controller: &mut dyn ChannelController,\n    ) -> Result<(), Box<dyn Error + Send + Sync>> {\n        if let Some(f) = &mut self.funcs.resolver_update {\n            return f(&mut self.data, update, config, channel_controller);\n        }\n        Ok(())\n    }\n\n    fn subchannel_update(\n        &mut self,\n        subchannel: Arc<dyn Subchannel>,\n        state: &SubchannelState,\n        channel_controller: &mut dyn ChannelController,\n    ) {\n        if let Some(f) = &self.funcs.subchannel_update {\n            f(&mut self.data, subchannel, state, channel_controller);\n        }\n    }\n\n    fn exit_idle(&mut self, channel_controller: &mut dyn ChannelController) {\n        todo!(\"Implement exit_idle for StubPolicy\")\n    }\n\n    fn work(&mut self, channel_controller: &mut dyn ChannelController) {\n        if let Some(f) = &self.funcs.work {\n            f(&mut self.data, channel_controller);\n        }\n    }\n}\n\n/// StubPolicyBuilder builds a StubLbPolicy.\n#[derive(Debug)]\npub(crate) struct StubPolicyBuilder {\n    name: &'static str,\n    funcs: StubPolicyFuncs,\n}\n\n#[derive(Serialize, Deserialize, Debug)]\n#[serde(rename_all = \"camelCase\")]\npub(super) struct MockConfig {\n    shuffle_address_list: Option<bool>,\n}\n\nimpl LbPolicyBuilder for StubPolicyBuilder {\n    fn build(&self, options: LbPolicyOptions) -> Box<dyn LbPolicy> {\n        let data = StubPolicyData::new(options);\n        Box::new(StubPolicy {\n            funcs: self.funcs.clone(),\n            data,\n        })\n    }\n\n    fn name(&self) -> &'static str {\n        self.name\n    }\n\n    fn parse_config(\n        &self,\n        config: &ParsedJsonLbConfig,\n    ) -> Result<Option<LbConfig>, Box<dyn Error + Send + Sync>> {\n        let cfg: MockConfig = match config.convert_to() {\n            Ok(c) => c,\n            Err(e) => {\n                return Err(format!(\"failed to parse JSON config: {}\", e).into());\n            }\n        };\n        Ok(Some(LbConfig::new(cfg)))\n    }\n}\n\npub(crate) fn reg_stub_policy(name: &'static str, funcs: StubPolicyFuncs) {\n    super::GLOBAL_LB_REGISTRY.add_builder(StubPolicyBuilder { name, funcs })\n}\n"
  },
  {
    "path": "grpc/src/client/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::fmt::Display;\nuse std::time::Instant;\n\nuse tonic::async_trait;\n\nuse crate::core::ClientResponseStreamItem;\nuse crate::core::RecvMessage;\nuse crate::core::RequestHeaders;\nuse crate::core::SendMessage;\n\npub mod channel;\npub mod interceptor;\npub mod service_config;\npub mod stream_util;\n\npub use channel::Channel;\npub use channel::ChannelOptions;\n\npub(crate) mod load_balancing;\npub(crate) mod name_resolution;\nmod subchannel;\npub(crate) mod transport;\n\n/// A representation of the current state of a gRPC channel, also used for the\n/// state of subchannels (individual connections within the channel).\n///\n/// A gRPC channel begins in the Idle state.  When an RPC is attempted, the\n/// channel will automatically transition to Connecting.  If connections to a\n/// backend service are available, the state becomes Ready.  Otherwise, if RPCs\n/// would fail due to a lack of connections, the state becomes TransientFailure\n/// and continues to attempt to reconnect.\n///\n/// Channels may re-enter the Idle state if they are unused for longer than\n/// their configured idleness timeout.\n#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]\npub enum ConnectivityState {\n    #[default]\n    Idle,\n    Connecting,\n    Ready,\n    TransientFailure,\n}\n\nimpl Display for ConnectivityState {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            ConnectivityState::Idle => write!(f, \"Idle\"),\n            ConnectivityState::Connecting => write!(f, \"Connecting\"),\n            ConnectivityState::Ready => write!(f, \"Ready\"),\n            ConnectivityState::TransientFailure => write!(f, \"TransientFailure\"),\n        }\n    }\n}\n\n/// Contains settings to configure an RPC.\n///\n/// Most applications will not need this type, and will set options via the\n/// generated (e.g. protobuf) APIs instead.\n#[derive(Default, Clone)]\n#[non_exhaustive]\npub struct CallOptions {\n    /// The deadline for the call.  If unset, the call may run indefinitely.\n    deadline: Option<Instant>,\n}\n\n/// A trait which may be implemented by types to perform RPCs (Remote Procedure\n/// Calls, often shortened to \"call\").\n///\n/// Most applications will not use this type directly, and will instead use the\n/// generated APIs (e.g.  protobuf) to perform RPCs instead.\n#[trait_variant::make(Send)]\npub trait Invoke: Sync {\n    type SendStream: SendStream + 'static;\n    type RecvStream: RecvStream + 'static;\n\n    /// Starts an RPC, returning the send and receive streams to interact with\n    /// it.\n    ///\n    /// Note that invoke is synchronous, which implies no pushback may be\n    /// enforced via execution flow.  If a call cannot be started or queued\n    /// locally, the returned SendStream and RecvStream may represent a\n    /// locally-erroring stream immediately instead.  However, SendStream and\n    /// RecvStream are asynchronous, and may block their first operations until\n    /// quota is available, a connection is ready, etc.\n    async fn invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream);\n}\n\n#[async_trait]\npub trait DynInvoke: Send + Sync {\n    async fn dyn_invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Box<dyn DynSendStream>, Box<dyn DynRecvStream>);\n}\n\n#[async_trait]\nimpl<T: Invoke> DynInvoke for T {\n    async fn dyn_invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Box<dyn DynSendStream>, Box<dyn DynRecvStream>) {\n        let (tx, rx) = self.invoke(headers, options).await;\n        (Box::new(tx), Box::new(rx))\n    }\n}\n\n// Like `Invoke`, but not reusable.  It is blanket implemented on references to\n// `Invoke`s.\n#[trait_variant::make(Send)]\npub trait InvokeOnce: Sync {\n    type SendStream: SendStream + 'static;\n    type RecvStream: RecvStream + 'static;\n\n    async fn invoke_once(\n        self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream);\n}\n\nimpl<T: Invoke> InvokeOnce for &T {\n    type SendStream = T::SendStream;\n    type RecvStream = T::RecvStream;\n\n    async fn invoke_once(\n        self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        self.invoke(headers, options).await\n    }\n}\n\n/// Represents the sending side of a client stream.  When a `SendStream` is\n/// dropped, the send side of the stream is closed.  Clients may continue to\n/// read from the RecvStream\n///\n/// Most applications will not need this type directly, and will use the\n/// generated APIs (e.g.  protobuf) to perform RPCs instead.\n#[trait_variant::make(Send)]\npub trait SendStream {\n    /// Sends T on the stream.  If Err(()) is returned, the message could not be\n    /// delivered because the stream was closed.  Future calls to SendStream\n    /// will do nothing.\n    ///\n    /// # Cancel safety\n    ///\n    /// This method is not intended to be cancellation safe.  If the returned\n    /// future is not polled to completion, the behavior of any subsequent calls\n    /// to the SendStream are undefined and data may be lost.\n    async fn send(&mut self, msg: &dyn SendMessage, options: SendOptions) -> Result<(), ()>;\n}\n\n#[async_trait]\npub trait DynSendStream: Send {\n    async fn dyn_send(&mut self, msg: &dyn SendMessage, options: SendOptions) -> Result<(), ()>;\n}\n\n#[async_trait]\nimpl<T: SendStream> DynSendStream for T {\n    async fn dyn_send(&mut self, msg: &dyn SendMessage, options: SendOptions) -> Result<(), ()> {\n        self.send(msg, options).await\n    }\n}\n\nimpl SendStream for Box<dyn DynSendStream> {\n    async fn send(&mut self, msg: &dyn SendMessage, options: SendOptions) -> Result<(), ()> {\n        (**self).dyn_send(msg, options).await\n    }\n}\n\n/// Contains settings to configure a send operation on a SendStream.\n///\n/// Most applications will not need this type directly, and will use the\n/// generated (e.g.  protobuf) APIs to configure RPCs instead.\n#[derive(Default, Clone)]\n#[non_exhaustive]\npub struct SendOptions {\n    /// Closes the stream immediately after sending this message.\n    pub final_msg: bool,\n    /// If set, compression will be disabled for this message.\n    pub disable_compression: bool,\n}\n\n/// Represents the receiving side of a client stream.  When a `RecvStream` is\n/// dropped, the associated call is cancelled if the server has not already\n/// terminated the stream.\n///\n/// Most applications will not need this type directly, and will use the\n/// generated APIs (e.g.  protobuf) to perform RPCs instead.\n#[trait_variant::make(Send)]\npub trait RecvStream {\n    /// Returns the next item on the stream.  If that item represents a message,\n    /// `msg` has been updated directly to contain the received message.\n    ///\n    /// # Cancel safety\n    ///\n    /// This method is not intended to be cancellation safe.  If the returned\n    /// future is not polled to completion, the behavior of any subsequent calls\n    /// to the RecvStream are undefined and data may be lost.\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem;\n}\n\n#[async_trait]\npub trait DynRecvStream: Send {\n    async fn dyn_next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem;\n}\n\n#[async_trait]\nimpl<T: RecvStream> DynRecvStream for T {\n    async fn dyn_next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n        self.next(msg).await\n    }\n}\n\nimpl RecvStream for Box<dyn DynRecvStream> {\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n        (**self).dyn_next(msg).await\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/name_resolution/backoff.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::time::Duration;\n\nuse rand::Rng;\n\n#[derive(Clone)]\npub(crate) struct BackoffConfig {\n    /// The amount of time to backoff after the first failure.\n    pub base_delay: Duration,\n\n    /// The factor with which to multiply backoffs after a\n    /// failed retry. Should ideally be greater than 1.\n    pub multiplier: f64,\n\n    /// The factor with which backoffs are randomized.\n    pub jitter: f64,\n\n    /// The upper bound of backoff delay.\n    pub max_delay: Duration,\n}\n\npub(crate) struct ExponentialBackoff {\n    config: BackoffConfig,\n\n    /// The delay for the next retry, without the random jitter. Store as f64\n    /// to avoid rounding errors.\n    next_delay_secs: f64,\n}\n\n/// This is a backoff configuration with the default values specified\n/// at https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.\n///\n/// This should be useful for callers who want to configure backoff with\n/// non-default values only for a subset of the options.\npub(crate) const DEFAULT_EXPONENTIAL_CONFIG: BackoffConfig = BackoffConfig {\n    base_delay: Duration::from_secs(1),\n    multiplier: 1.6,\n    jitter: 0.2,\n    max_delay: Duration::from_secs(120),\n};\n\nimpl BackoffConfig {\n    fn validate(&self) -> Result<(), &'static str> {\n        // Check that the arguments are in valid ranges.\n        // 0 <= base_dealy <= max_delay\n        if self.base_delay > self.max_delay {\n            Err(\"base_delay must be greater than max_delay\")?;\n        }\n        // 1 <= multiplier\n        if self.multiplier < 1.0 {\n            Err(\"multiplier must be greater than 1.0\")?;\n        }\n        // 0 <= jitter <= 1\n        if self.jitter < 0.0 {\n            Err(\"jitter must be greater than or equal to 0\")?;\n        }\n        if self.jitter > 1.0 {\n            Err(\"jitter must be less than or equal to 1\")?\n        }\n        Ok(())\n    }\n}\n\nimpl ExponentialBackoff {\n    pub fn new(config: BackoffConfig) -> Result<Self, &'static str> {\n        config.validate()?;\n        let next_delay_secs = config.base_delay.as_secs_f64();\n        Ok(ExponentialBackoff {\n            config,\n            next_delay_secs,\n        })\n    }\n\n    pub fn reset(&mut self) {\n        self.next_delay_secs = self.config.base_delay.as_secs_f64();\n    }\n\n    pub fn backoff_duration(&mut self) -> Duration {\n        let next_delay = self.next_delay_secs;\n        let cur_delay =\n            next_delay * (1.0 + self.config.jitter * rand::rng().random_range(-1.0..1.0));\n        self.next_delay_secs = self\n            .config\n            .max_delay\n            .as_secs_f64()\n            .min(next_delay * self.config.multiplier);\n        Duration::from_secs_f64(cur_delay)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::time::Duration;\n\n    use crate::client::name_resolution::backoff::BackoffConfig;\n    use crate::client::name_resolution::backoff::DEFAULT_EXPONENTIAL_CONFIG;\n    use crate::client::name_resolution::backoff::ExponentialBackoff;\n\n    // Epsilon for floating point comparisons if needed, though Duration\n    // comparisons are often better.\n    const EPSILON: f64 = 1e-9;\n\n    #[test]\n    fn default_config_is_valid() {\n        let result = ExponentialBackoff::new(DEFAULT_EXPONENTIAL_CONFIG.clone());\n        assert!(result.is_ok());\n    }\n\n    #[test]\n    fn base_less_than_max() {\n        let config = BackoffConfig {\n            base_delay: Duration::from_secs(10),\n            multiplier: 123.0,\n            jitter: 0.0,\n            max_delay: Duration::from_secs(100),\n        };\n        let mut backoff = ExponentialBackoff::new(config).unwrap();\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(10));\n    }\n\n    #[test]\n    fn base_more_than_max() {\n        let config = BackoffConfig {\n            multiplier: 123.0,\n            jitter: 0.0,\n            base_delay: Duration::from_secs(100),\n            max_delay: Duration::from_secs(10),\n        };\n        let result = ExponentialBackoff::new(config);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn negative_multiplier() {\n        let config = BackoffConfig {\n            multiplier: -123.0,\n            jitter: 0.0,\n            base_delay: Duration::from_secs(10),\n            max_delay: Duration::from_secs(100),\n        };\n        let result = ExponentialBackoff::new(config);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn negative_jitter() {\n        let config = BackoffConfig {\n            multiplier: 1.0,\n            jitter: -10.0,\n            base_delay: Duration::from_secs(10),\n            max_delay: Duration::from_secs(100),\n        };\n        let result = ExponentialBackoff::new(config);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn jitter_greater_than_one() {\n        let config = BackoffConfig {\n            multiplier: 1.0,\n            jitter: 2.0,\n            base_delay: Duration::from_secs(10),\n            max_delay: Duration::from_secs(100),\n        };\n        let result = ExponentialBackoff::new(config);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn backoff_reset_no_jitter() {\n        let config = BackoffConfig {\n            multiplier: 2.0,\n            jitter: 0.0,\n            base_delay: Duration::from_secs(1),\n            max_delay: Duration::from_secs(15),\n        };\n        let mut backoff = ExponentialBackoff::new(config.clone()).unwrap();\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(1));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(2));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(4));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(8));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(15));\n        // Duration is capped to max_delay.\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(15));\n\n        // reset and repeat.\n        backoff.reset();\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(1));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(2));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(4));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(8));\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(15));\n        // Duration is capped to max_delay.\n        assert_eq!(backoff.backoff_duration(), Duration::from_secs(15));\n    }\n\n    #[test]\n    fn backoff_with_jitter() {\n        let config = BackoffConfig {\n            multiplier: 2.0,\n            jitter: 0.2,\n            base_delay: Duration::from_secs(1),\n            max_delay: Duration::from_secs(15),\n        };\n        let mut backoff = ExponentialBackoff::new(config.clone()).unwrap();\n        // 0.8 <= duration <= 1.2.\n        let duration = backoff.backoff_duration();\n        assert!(duration.gt(&Duration::from_secs_f64(0.8 - EPSILON)));\n        assert!(duration.lt(&Duration::from_secs_f64(1.2 + EPSILON)));\n        // 1.6 <= duration <= 2.4.\n        let duration = backoff.backoff_duration();\n        assert!(duration.gt(&Duration::from_secs_f64(1.6 - EPSILON)));\n        assert!(duration.lt(&Duration::from_secs_f64(2.4 + EPSILON)));\n        // 3.2 <= duration <= 4.8.\n        let duration = backoff.backoff_duration();\n        assert!(duration.gt(&Duration::from_secs_f64(3.2 - EPSILON)));\n        assert!(duration.lt(&Duration::from_secs_f64(4.8 + EPSILON)));\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/name_resolution/dns/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\n//! This module implements a DNS resolver to be installed as the default resolver\n//! in grpc.\n\nuse std::net::IpAddr;\nuse std::net::SocketAddr;\nuse std::sync::Arc;\nuse std::sync::atomic::AtomicU64;\nuse std::sync::atomic::Ordering;\nuse std::time::Duration;\nuse std::time::SystemTime;\n\nuse parking_lot::Mutex;\nuse tokio::sync::Notify;\nuse url::Host;\n\nuse crate::byte_str::ByteStr;\nuse crate::client::name_resolution::Address;\nuse crate::client::name_resolution::ChannelController;\nuse crate::client::name_resolution::Endpoint;\nuse crate::client::name_resolution::NopResolver;\nuse crate::client::name_resolution::Resolver;\nuse crate::client::name_resolution::ResolverBuilder;\nuse crate::client::name_resolution::ResolverOptions;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::client::name_resolution::TCP_IP_NETWORK_TYPE;\nuse crate::client::name_resolution::Target;\nuse crate::client::name_resolution::backoff::BackoffConfig;\nuse crate::client::name_resolution::backoff::DEFAULT_EXPONENTIAL_CONFIG;\nuse crate::client::name_resolution::backoff::ExponentialBackoff;\nuse crate::client::name_resolution::global_registry;\nuse crate::rt::BoxedTaskHandle;\nuse crate::rt::{self};\n\n#[cfg(test)]\nmod test;\n\nconst DEFAULT_PORT: u16 = 443;\nconst DEFAULT_DNS_PORT: u16 = 53;\n\n/// This specifies the maximum duration for a DNS resolution request.\n/// If the timeout expires before a response is received, the request will be\n/// canceled.\n///\n/// It is recommended to set this value at application startup. Avoid modifying\n/// this variable after initialization.\nstatic RESOLVING_TIMEOUT_MS: AtomicU64 = AtomicU64::new(30_000); // 30 seconds\n\n/// This is the minimum interval at which re-resolutions are allowed. This helps\n/// to prevent excessive re-resolution.\nstatic MIN_RESOLUTION_INTERVAL_MS: AtomicU64 = AtomicU64::new(30_000); // 30 seconds\n\nfn get_resolving_timeout() -> Duration {\n    Duration::from_millis(RESOLVING_TIMEOUT_MS.load(Ordering::Relaxed))\n}\n\n/// Sets the maximum duration for DNS resolution requests.\n///\n/// This function affects the global timeout used by all channels using the DNS\n/// name resolver scheme.\n///\n/// It must be called only at application startup, before any gRPC calls are\n/// made.\n///\n/// The default value is 30 seconds. Setting the timeout too low may result in\n/// premature timeouts during resolution, while setting it too high may lead to\n/// unnecessary delays in service discovery. Choose a value appropriate for your\n/// specific needs and network environment.\npub(crate) fn set_resolving_timeout(duration: Duration) {\n    RESOLVING_TIMEOUT_MS.store(duration.as_millis() as u64, Ordering::Relaxed);\n}\n\nfn get_min_resolution_interval() -> Duration {\n    Duration::from_millis(MIN_RESOLUTION_INTERVAL_MS.load(Ordering::Relaxed))\n}\n\n/// Sets the default minimum interval at which DNS re-resolutions are allowed.\n/// This helps to prevent excessive re-resolution.\n///\n/// It must be called only at application startup, before any gRPC calls are\n/// made.\npub(crate) fn set_min_resolution_interval(duration: Duration) {\n    MIN_RESOLUTION_INTERVAL_MS.store(duration.as_millis() as u64, Ordering::Relaxed);\n}\n\npub(crate) fn reg() {\n    global_registry().add_builder(Box::new(Builder {}));\n}\n\nstruct Builder {}\n\nstruct DnsOptions {\n    min_resolution_interval: Duration,\n    resolving_timeout: Duration,\n    backoff_config: BackoffConfig,\n    host: String,\n    port: u16,\n}\n\nimpl DnsResolver {\n    fn new(\n        dns_client: Box<dyn rt::DnsResolver>,\n        options: ResolverOptions,\n        dns_opts: DnsOptions,\n    ) -> Self {\n        let state = Arc::new(Mutex::new(InternalState {\n            addrs: Ok(Vec::new()),\n            channel_response: None,\n        }));\n        let state_copy = state.clone();\n        let resolve_now_notify = Arc::new(Notify::new());\n        let channel_updated_notify = Arc::new(Notify::new());\n        let channel_updated_rx = channel_updated_notify.clone();\n        let resolve_now_rx = resolve_now_notify.clone();\n\n        let runtime = options.runtime.clone();\n        let work_scheduler = options.work_scheduler.clone();\n        let handle = options.runtime.spawn(Box::pin(async move {\n            let mut backoff = ExponentialBackoff::new(dns_opts.backoff_config.clone())\n                .expect(\"default exponential config must be valid\");\n            let state = state_copy;\n            loop {\n                let mut lookup_fut = dns_client.lookup_host_name(&dns_opts.host);\n                let mut timeout_fut = runtime.sleep(dns_opts.resolving_timeout);\n                let addrs = tokio::select! {\n                    result = &mut lookup_fut => {\n                        match result {\n                            Ok(ips) => {\n                                let addrs = ips\n                                    .into_iter()\n                                    .map(|ip| SocketAddr::new(ip, dns_opts.port))\n                                    .collect();\n                                Ok(addrs)\n                            }\n                            Err(err) => Err(err),\n                        }\n                    }\n                    _ = &mut timeout_fut => {\n                        Err(\"Timed out waiting for DNS resolution\".to_string())\n                    }\n                };\n                {\n                    state.lock().addrs = addrs;\n                }\n                work_scheduler.schedule_work();\n                channel_updated_rx.notified().await;\n                let channel_response = { state.lock().channel_response.take() };\n                let next_resoltion_time = if channel_response.is_some() {\n                    SystemTime::now()\n                        .checked_add(backoff.backoff_duration())\n                        .unwrap()\n                } else {\n                    // Success resolving, wait for the next resolve_now. However,\n                    // also wait MIN_RESOLUTION_INTERVAL at the very least to prevent\n                    // constantly re-resolving.\n                    backoff.reset();\n                    let res_time = SystemTime::now()\n                        .checked_add(dns_opts.min_resolution_interval)\n                        .unwrap();\n                    _ = resolve_now_rx.notified().await;\n                    res_time\n                };\n                // Wait till next resolution time.\n                let Ok(duration) = next_resoltion_time.duration_since(SystemTime::now()) else {\n                    continue; // Time has already passed.\n                };\n                runtime.sleep(duration).await;\n            }\n        }));\n\n        Self {\n            state,\n            task_handle: handle,\n            resolve_now_notifier: resolve_now_notify,\n            channel_update_notifier: channel_updated_notify,\n        }\n    }\n}\n\nimpl ResolverBuilder for Builder {\n    fn build(&self, target: &Target, options: ResolverOptions) -> Box<dyn Resolver> {\n        let parsed = match parse_endpoint_and_authority(target) {\n            Ok(res) => res,\n            Err(err) => return nop_resolver_for_err(err.to_string(), options),\n        };\n        let endpoint = parsed.endpoint;\n        let host = match endpoint.host {\n            Host::Domain(d) => d,\n            Host::Ipv4(ipv4) => {\n                return nop_resolver_for_ip(IpAddr::V4(ipv4), endpoint.port, options);\n            }\n            Host::Ipv6(ipv6) => {\n                return nop_resolver_for_ip(IpAddr::V6(ipv6), endpoint.port, options);\n            }\n        };\n        let authority = parsed.authority;\n        let dns_client = match options.runtime.get_dns_resolver(rt::ResolverOptions {\n            server_addr: authority,\n        }) {\n            Ok(dns) => dns,\n            Err(err) => return nop_resolver_for_err(err.to_string(), options),\n        };\n        let dns_opts = DnsOptions {\n            min_resolution_interval: get_min_resolution_interval(),\n            resolving_timeout: get_resolving_timeout(),\n            backoff_config: DEFAULT_EXPONENTIAL_CONFIG,\n            host,\n            port: endpoint.port,\n        };\n        Box::new(DnsResolver::new(dns_client, options, dns_opts))\n    }\n\n    fn scheme(&self) -> &'static str {\n        \"dns\"\n    }\n\n    fn is_valid_uri(&self, target: &Target) -> bool {\n        if let Err(err) = parse_endpoint_and_authority(target) {\n            eprintln!(\"{err}\");\n            false\n        } else {\n            true\n        }\n    }\n}\n\nstruct DnsResolver {\n    state: Arc<Mutex<InternalState>>,\n    task_handle: BoxedTaskHandle,\n    resolve_now_notifier: Arc<Notify>,\n    channel_update_notifier: Arc<Notify>,\n}\n\nstruct InternalState {\n    addrs: Result<Vec<SocketAddr>, String>,\n    // Error from the latest call to channel_controller.update().\n    channel_response: Option<String>,\n}\n\nimpl Resolver for DnsResolver {\n    fn resolve_now(&mut self) {\n        self.resolve_now_notifier.notify_one();\n    }\n\n    fn work(&mut self, channel_controller: &mut dyn ChannelController) {\n        let mut state = self.state.lock();\n        let endpoint_result = match &state.addrs {\n            Ok(addrs) => {\n                let endpoints: Vec<_> = addrs\n                    .iter()\n                    .map(|a| Endpoint {\n                        addresses: vec![Address {\n                            network_type: TCP_IP_NETWORK_TYPE,\n                            address: ByteStr::from(a.to_string()),\n                            ..Default::default()\n                        }],\n                        ..Default::default()\n                    })\n                    .collect();\n                Ok(endpoints)\n            }\n            Err(err) => Err(err.to_string()),\n        };\n        let update = ResolverUpdate {\n            endpoints: endpoint_result,\n            ..Default::default()\n        };\n        let status = channel_controller.update(update);\n        state.channel_response = status.err();\n        self.channel_update_notifier.notify_one();\n    }\n}\n\nimpl Drop for DnsResolver {\n    fn drop(&mut self) {\n        self.task_handle.abort();\n    }\n}\n\n#[derive(Eq, PartialEq, Debug)]\nstruct HostPort {\n    host: Host<String>,\n    port: u16,\n}\n\n#[derive(Eq, PartialEq, Debug)]\nstruct ParseResult {\n    endpoint: HostPort,\n    authority: Option<SocketAddr>,\n}\n\nfn parse_endpoint_and_authority(target: &Target) -> Result<ParseResult, String> {\n    // Parse the endpoint.\n    let endpoint = target.path();\n    let endpoint = endpoint.strip_prefix(\"/\").unwrap_or(endpoint);\n    let parse_result = parse_host_port(endpoint, DEFAULT_PORT)\n        .map_err(|err| format!(\"Failed to parse target {target}: {err}\"))?;\n    let endpoint = parse_result.ok_or(\"Received empty endpoint host.\".to_string())?;\n\n    // Parse the authority.\n    let authority = target.authority_host_port();\n    if authority.is_empty() {\n        return Ok(ParseResult {\n            endpoint,\n            authority: None,\n        });\n    }\n    let parse_result = parse_host_port(&authority, DEFAULT_DNS_PORT)\n        .map_err(|err| format!(\"Failed to parse DNS authority {target}: {err}\"))?;\n    let Some(authority) = parse_result else {\n        return Ok(ParseResult {\n            endpoint,\n            authority: None,\n        });\n    };\n    let authority = match authority.host {\n        Host::Ipv4(ipv4) => SocketAddr::new(IpAddr::V4(ipv4), authority.port),\n        Host::Ipv6(ipv6) => SocketAddr::new(IpAddr::V6(ipv6), authority.port),\n        _ => {\n            return Err(format!(\"Received non-IP DNS authority {}\", authority.host));\n        }\n    };\n    Ok(ParseResult {\n        endpoint,\n        authority: Some(authority),\n    })\n}\n\n/// Takes the user input string of the format \"host:port\" and default port,\n/// returns the parsed host and port. If string doesn't specify a port, the\n/// default_port is returned. If the string doesn't specify the host,\n/// Ok(None) is returned.\nfn parse_host_port(host_and_port: &str, default_port: u16) -> Result<Option<HostPort>, String> {\n    // We need to use the https scheme otherwise url::Url::parse doesn't convert\n    // IP addresses to Host::Ipv4 or Host::Ipv6 if they could represent valid\n    // domains.\n    let url = format!(\"https://{host_and_port}\");\n    let url = url.parse::<url::Url>().map_err(|err| err.to_string())?;\n    let port = url.port().unwrap_or(default_port);\n    let host = match url.host() {\n        Some(host) => host,\n        None => return Ok(None),\n    };\n    // Convert the domain to an owned string.\n    let host = match host {\n        Host::Domain(s) => Host::Domain(s.to_owned()),\n        Host::Ipv4(ip) => Host::Ipv4(ip),\n        Host::Ipv6(ip) => Host::Ipv6(ip),\n    };\n    Ok(Some(HostPort { host, port }))\n}\n\nfn nop_resolver_for_ip(ip: IpAddr, port: u16, options: ResolverOptions) -> Box<dyn Resolver> {\n    options.work_scheduler.schedule_work();\n    Box::new(NopResolver {\n        update: ResolverUpdate {\n            endpoints: Ok(vec![Endpoint {\n                addresses: vec![Address {\n                    network_type: TCP_IP_NETWORK_TYPE,\n                    address: ByteStr::from(SocketAddr::new(ip, port).to_string()),\n                    ..Default::default()\n                }],\n                ..Default::default()\n            }]),\n            ..Default::default()\n        },\n    })\n}\n\nfn nop_resolver_for_err(err: String, options: ResolverOptions) -> Box<dyn Resolver> {\n    options.work_scheduler.schedule_work();\n    Box::new(NopResolver {\n        update: ResolverUpdate {\n            endpoints: Err(err),\n            ..Default::default()\n        },\n    })\n}\n"
  },
  {
    "path": "grpc/src/client/name_resolution/dns/test.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse tokio::sync::mpsc::UnboundedSender;\nuse tokio::sync::mpsc::{self};\nuse url::Host;\n\nuse crate::client::name_resolution::ChannelController;\nuse crate::client::name_resolution::Resolver;\nuse crate::client::name_resolution::ResolverOptions;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::client::name_resolution::Target;\nuse crate::client::name_resolution::WorkScheduler;\nuse crate::client::name_resolution::backoff::BackoffConfig;\nuse crate::client::name_resolution::backoff::DEFAULT_EXPONENTIAL_CONFIG;\nuse crate::client::name_resolution::dns::DnsOptions;\nuse crate::client::name_resolution::dns::DnsResolver;\nuse crate::client::name_resolution::dns::HostPort;\nuse crate::client::name_resolution::dns::ParseResult;\nuse crate::client::name_resolution::dns::get_min_resolution_interval;\nuse crate::client::name_resolution::dns::get_resolving_timeout;\nuse crate::client::name_resolution::dns::parse_endpoint_and_authority;\nuse crate::client::name_resolution::dns::reg;\nuse crate::client::name_resolution::global_registry;\nuse crate::client::service_config::ServiceConfig;\nuse crate::rt::BoxFuture;\nuse crate::rt::GrpcRuntime;\nuse crate::rt::TcpOptions;\nuse crate::rt::tokio::TokioRuntime;\nuse crate::rt::{self};\n\nconst DEFAULT_TEST_SHORT_TIMEOUT: Duration = Duration::from_millis(10);\n\n#[test]\npub(crate) fn target_parsing() {\n    struct TestCase {\n        input: &'static str,\n        want_result: Result<ParseResult, String>,\n    }\n    let test_cases = vec![\n        TestCase {\n            input: \"dns:///grpc.io\",\n            want_result: Ok(ParseResult {\n                endpoint: HostPort {\n                    host: Host::Domain(\"grpc.io\".to_string()),\n                    port: 443,\n                },\n                authority: None,\n            }),\n        },\n        TestCase {\n            input: \"dns:///grpc.io:1234\",\n            want_result: Ok(ParseResult {\n                endpoint: HostPort {\n                    host: Host::Domain(\"grpc.io\".to_string()),\n                    port: 1234,\n                },\n                authority: None,\n            }),\n        },\n        TestCase {\n            input: \"dns://8.8.8.8/grpc.io:1234\",\n            want_result: Ok(ParseResult {\n                endpoint: HostPort {\n                    host: Host::Domain(\"grpc.io\".to_string()),\n                    port: 1234,\n                },\n                authority: Some(\"8.8.8.8:53\".parse().unwrap()),\n            }),\n        },\n        TestCase {\n            input: \"dns://8.8.8.8:5678/grpc.io:1234/abc\",\n            want_result: Ok(ParseResult {\n                endpoint: HostPort {\n                    host: Host::Domain(\"grpc.io\".to_string()),\n                    port: 1234,\n                },\n                authority: Some(\"8.8.8.8:5678\".parse().unwrap()),\n            }),\n        },\n        TestCase {\n            input: \"dns://[::1]:5678/grpc.io:1234/abc\",\n            want_result: Ok(ParseResult {\n                endpoint: HostPort {\n                    host: Host::Domain(\"grpc.io\".to_string()),\n                    port: 1234,\n                },\n                authority: Some(\"[::1]:5678\".parse().unwrap()),\n            }),\n        },\n        TestCase {\n            input: \"dns://[fe80::1]:5678/127.0.0.1:1234/abc\",\n            want_result: Ok(ParseResult {\n                endpoint: HostPort {\n                    host: Host::Ipv4(\"127.0.0.1\".parse().unwrap()),\n                    port: 1234,\n                },\n                authority: Some(\"[fe80::1]:5678\".parse().unwrap()),\n            }),\n        },\n        TestCase {\n            input: \"dns:///[fe80::1%80]:5678/abc\",\n            want_result: Err(\"SocketAddr doesn't support IPv6 addresses with zones\".to_string()),\n        },\n        TestCase {\n            input: \"dns:///:5678/abc\",\n            want_result: Err(\"Empty host with port\".to_string()),\n        },\n        TestCase {\n            input: \"dns:///grpc.io:abc/abc\",\n            want_result: Err(\"Non numeric port\".to_string()),\n        },\n        TestCase {\n            input: \"dns:///grpc.io:/\",\n            want_result: Ok(ParseResult {\n                endpoint: HostPort {\n                    host: Host::Domain(\"grpc.io\".to_string()),\n                    port: 443,\n                },\n                authority: None,\n            }),\n        },\n        TestCase {\n            input: \"dns:///:\",\n            want_result: Err(\"No host and port\".to_string()),\n        },\n        TestCase {\n            input: \"dns:///[2001:db8:a0b:12f0::1\",\n            want_result: Err(\"Invalid address\".to_string()),\n        },\n    ];\n\n    for tc in test_cases {\n        let target: Target = tc.input.parse().unwrap();\n        let got = parse_endpoint_and_authority(&target);\n        if got.is_err() != tc.want_result.is_err() {\n            panic!(\n                \"Got error {:?}, want error: {:?}\",\n                got.err(),\n                tc.want_result.err()\n            );\n        }\n        if got.is_err() {\n            continue;\n        }\n        assert_eq!(got.unwrap(), tc.want_result.unwrap());\n    }\n}\n\nstruct FakeWorkScheduler {\n    work_tx: UnboundedSender<()>,\n}\n\nimpl WorkScheduler for FakeWorkScheduler {\n    fn schedule_work(&self) {\n        self.work_tx.send(()).unwrap();\n    }\n}\n\nstruct FakeChannelController {\n    update_result: Result<(), String>,\n    update_tx: UnboundedSender<ResolverUpdate>,\n}\n\nimpl ChannelController for FakeChannelController {\n    fn update(&mut self, update: ResolverUpdate) -> Result<(), String> {\n        println!(\"Received resolver update: {:?}\", &update);\n        self.update_tx.send(update).unwrap();\n        self.update_result.clone()\n    }\n\n    fn parse_service_config(&self, _: &str) -> Result<ServiceConfig, String> {\n        Err(\"Unimplemented\".to_string())\n    }\n}\n\n#[tokio::test]\npub(crate) async fn dns_basic() {\n    reg();\n    let builder = global_registry().get(\"dns\").unwrap();\n    let target = &\"dns:///localhost:1234\".parse().unwrap();\n    let (work_tx, mut work_rx) = mpsc::unbounded_channel();\n    let work_scheduler = Arc::new(FakeWorkScheduler {\n        work_tx: work_tx.clone(),\n    });\n    let opts = ResolverOptions {\n        authority: \"ignored\".to_string(),\n        runtime: rt::default_runtime(),\n        work_scheduler: work_scheduler.clone(),\n    };\n    let mut resolver = builder.build(target, opts);\n\n    // Wait for schedule work to be called.\n    work_rx.recv().await.unwrap();\n    let (update_tx, mut update_rx) = mpsc::unbounded_channel();\n    let mut channel_controller = FakeChannelController {\n        update_tx,\n        update_result: Ok(()),\n    };\n    resolver.work(&mut channel_controller);\n    // A successful endpoint update should be received.\n    let update = update_rx.recv().await.unwrap();\n    assert!(update.endpoints.unwrap().len() > 1);\n}\n\n#[tokio::test]\npub(crate) async fn invalid_target() {\n    reg();\n    let builder = global_registry().get(\"dns\").unwrap();\n    let target = &\"dns:///:1234\".parse().unwrap();\n    let (work_tx, mut work_rx) = mpsc::unbounded_channel();\n    let work_scheduler = Arc::new(FakeWorkScheduler {\n        work_tx: work_tx.clone(),\n    });\n    let opts = ResolverOptions {\n        authority: \"ignored\".to_string(),\n        runtime: rt::default_runtime(),\n        work_scheduler: work_scheduler.clone(),\n    };\n    let mut resolver = builder.build(target, opts);\n\n    // Wait for schedule work to be called.\n    work_rx.recv().await.unwrap();\n    let (update_tx, mut update_rx) = mpsc::unbounded_channel();\n    let mut channel_controller = FakeChannelController {\n        update_tx,\n        update_result: Ok(()),\n    };\n    resolver.work(&mut channel_controller);\n    // An error endpoint update should be received.\n    let update = update_rx.recv().await.unwrap();\n    assert!(\n        update\n            .endpoints\n            .err()\n            .unwrap()\n            .contains(&target.to_string())\n    );\n}\n\n#[derive(Clone, Debug)]\nstruct FakeDns {\n    latency: Duration,\n    lookup_result: Result<Vec<std::net::IpAddr>, String>,\n}\n\n#[tonic::async_trait]\nimpl rt::DnsResolver for FakeDns {\n    async fn lookup_host_name(&self, _: &str) -> Result<Vec<std::net::IpAddr>, String> {\n        tokio::time::sleep(self.latency).await;\n        self.lookup_result.clone()\n    }\n\n    async fn lookup_txt(&self, _: &str) -> Result<Vec<String>, String> {\n        Err(\"unimplemented\".to_string())\n    }\n}\n\n#[derive(Debug)]\nstruct FakeRuntime {\n    inner: TokioRuntime,\n    dns: FakeDns,\n}\n\nimpl rt::Runtime for FakeRuntime {\n    fn spawn(\n        &self,\n        task: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,\n    ) -> Box<dyn rt::TaskHandle> {\n        self.inner.spawn(task)\n    }\n\n    fn get_dns_resolver(&self, _: rt::ResolverOptions) -> Result<Box<dyn rt::DnsResolver>, String> {\n        Ok(Box::new(self.dns.clone()))\n    }\n\n    fn sleep(&self, duration: std::time::Duration) -> Pin<Box<dyn rt::Sleep>> {\n        self.inner.sleep(duration)\n    }\n\n    fn tcp_stream(\n        &self,\n        target: std::net::SocketAddr,\n        opts: rt::TcpOptions,\n    ) -> Pin<Box<dyn Future<Output = Result<Box<dyn rt::GrpcEndpoint>, String>> + Send>> {\n        self.inner.tcp_stream(target, opts)\n    }\n\n    fn listen_tcp(\n        &self,\n        _addr: std::net::SocketAddr,\n        _opts: TcpOptions,\n    ) -> BoxFuture<Result<Box<dyn rt::TcpListener>, String>> {\n        unimplemented!()\n    }\n}\n\n#[tokio::test]\npub(crate) async fn dns_lookup_error() {\n    reg();\n    let builder = global_registry().get(\"dns\").unwrap();\n    let target = &\"dns:///grpc.io:1234\".parse().unwrap();\n    let (work_tx, mut work_rx) = mpsc::unbounded_channel();\n    let work_scheduler = Arc::new(FakeWorkScheduler {\n        work_tx: work_tx.clone(),\n    });\n    let runtime = FakeRuntime {\n        inner: TokioRuntime::default(),\n        dns: FakeDns {\n            latency: Duration::from_secs(0),\n            lookup_result: Err(\"test_error\".to_string()),\n        },\n    };\n    let opts = ResolverOptions {\n        authority: \"ignored\".to_string(),\n        runtime: GrpcRuntime::new(runtime),\n        work_scheduler: work_scheduler.clone(),\n    };\n    let mut resolver = builder.build(target, opts);\n\n    // Wait for schedule work to be called.\n    work_rx.recv().await.unwrap();\n    let (update_tx, mut update_rx) = mpsc::unbounded_channel();\n    let mut channel_controller = FakeChannelController {\n        update_tx,\n        update_result: Ok(()),\n    };\n    resolver.work(&mut channel_controller);\n    // An error endpoint update should be received.\n    let update = update_rx.recv().await.unwrap();\n    assert!(update.endpoints.err().unwrap().contains(\"test_error\"));\n}\n\n#[tokio::test]\npub(crate) async fn dns_lookup_timeout() {\n    let (work_tx, mut work_rx) = mpsc::unbounded_channel();\n    let work_scheduler = Arc::new(FakeWorkScheduler {\n        work_tx: work_tx.clone(),\n    });\n    let runtime = FakeRuntime {\n        inner: TokioRuntime::default(),\n        dns: FakeDns {\n            latency: Duration::from_secs(20),\n            lookup_result: Ok(Vec::new()),\n        },\n    };\n    let dns_client = runtime.dns.clone();\n    let opts = ResolverOptions {\n        authority: \"ignored\".to_string(),\n        runtime: GrpcRuntime::new(runtime),\n        work_scheduler: work_scheduler.clone(),\n    };\n    let dns_opts = DnsOptions {\n        min_resolution_interval: get_min_resolution_interval(),\n        resolving_timeout: DEFAULT_TEST_SHORT_TIMEOUT,\n        backoff_config: DEFAULT_EXPONENTIAL_CONFIG,\n        host: \"grpc.io\".to_string(),\n        port: 1234,\n    };\n    let mut resolver = DnsResolver::new(Box::new(dns_client), opts, dns_opts);\n\n    // Wait for schedule work to be called.\n    work_rx.recv().await.unwrap();\n    let (update_tx, mut update_rx) = mpsc::unbounded_channel();\n    let mut channel_controller = FakeChannelController {\n        update_tx,\n        update_result: Ok(()),\n    };\n    resolver.work(&mut channel_controller);\n\n    // An error endpoint update should be received.\n    let update = update_rx.recv().await.unwrap();\n    assert!(update.endpoints.err().unwrap().contains(\"Timed out\"));\n}\n\n#[tokio::test]\npub(crate) async fn rate_limit() {\n    let (work_tx, mut work_rx) = mpsc::unbounded_channel();\n    let work_scheduler = Arc::new(FakeWorkScheduler {\n        work_tx: work_tx.clone(),\n    });\n    let opts = ResolverOptions {\n        authority: \"ignored\".to_string(),\n        runtime: rt::default_runtime(),\n        work_scheduler: work_scheduler.clone(),\n    };\n    let dns_client = opts\n        .runtime\n        .get_dns_resolver(rt::ResolverOptions { server_addr: None })\n        .unwrap();\n    let dns_opts = DnsOptions {\n        min_resolution_interval: Duration::from_secs(20),\n        resolving_timeout: get_resolving_timeout(),\n        backoff_config: DEFAULT_EXPONENTIAL_CONFIG,\n        host: \"localhost\".to_string(),\n        port: 1234,\n    };\n    let mut resolver = DnsResolver::new(dns_client, opts, dns_opts);\n\n    // Wait for schedule work to be called.\n    work_rx.recv().await.unwrap();\n    let (update_tx, mut update_rx) = mpsc::unbounded_channel();\n    let mut channel_controller = FakeChannelController {\n        update_tx,\n        update_result: Ok(()),\n    };\n    resolver.work(&mut channel_controller);\n    // A successful endpoint update should be received.\n    let update = update_rx.recv().await.unwrap();\n    assert!(update.endpoints.unwrap().len() > 1);\n\n    // Call resolve_now repeatedly, new updates should not be produced.\n    for _ in 0..5 {\n        resolver.resolve_now();\n        tokio::select! {\n            _ = work_rx.recv() => {\n                panic!(\"Received unexpected work request from resolver\");\n            }\n            _ = tokio::time::sleep(DEFAULT_TEST_SHORT_TIMEOUT) => {\n                println!(\"No work requested from resolver.\");\n            }\n        };\n    }\n}\n\n#[tokio::test]\npub(crate) async fn re_resolution_after_success() {\n    let (work_tx, mut work_rx) = mpsc::unbounded_channel();\n    let work_scheduler = Arc::new(FakeWorkScheduler {\n        work_tx: work_tx.clone(),\n    });\n    let opts = ResolverOptions {\n        authority: \"ignored\".to_string(),\n        runtime: rt::default_runtime(),\n        work_scheduler: work_scheduler.clone(),\n    };\n    let dns_opts = DnsOptions {\n        min_resolution_interval: Duration::from_millis(1),\n        resolving_timeout: get_resolving_timeout(),\n        backoff_config: DEFAULT_EXPONENTIAL_CONFIG,\n        host: \"localhost\".to_string(),\n        port: 1234,\n    };\n    let dns_client = opts\n        .runtime\n        .get_dns_resolver(rt::ResolverOptions { server_addr: None })\n        .unwrap();\n    let mut resolver = DnsResolver::new(dns_client, opts, dns_opts);\n\n    // Wait for schedule work to be called.\n    work_rx.recv().await.unwrap();\n    let (update_tx, mut update_rx) = mpsc::unbounded_channel();\n    let mut channel_controller = FakeChannelController {\n        update_tx,\n        update_result: Ok(()),\n    };\n    resolver.work(&mut channel_controller);\n    // A successful endpoint update should be received.\n    let update = update_rx.recv().await.unwrap();\n    assert!(update.endpoints.unwrap().len() > 1);\n\n    // Call resolve_now, a new update should be produced.\n    resolver.resolve_now();\n    work_rx.recv().await.unwrap();\n    resolver.work(&mut channel_controller);\n    let update = update_rx.recv().await.unwrap();\n    assert!(update.endpoints.unwrap().len() > 1);\n}\n\n#[tokio::test]\npub(crate) async fn backoff_on_error() {\n    let (work_tx, mut work_rx) = mpsc::unbounded_channel();\n    let work_scheduler = Arc::new(FakeWorkScheduler {\n        work_tx: work_tx.clone(),\n    });\n    let opts = ResolverOptions {\n        authority: \"ignored\".to_string(),\n        runtime: rt::default_runtime(),\n        work_scheduler: work_scheduler.clone(),\n    };\n    let dns_opts = DnsOptions {\n        min_resolution_interval: Duration::from_millis(1),\n        resolving_timeout: get_resolving_timeout(),\n        // Speed up the backoffs to make the test run faster.\n        backoff_config: BackoffConfig {\n            base_delay: Duration::from_millis(1),\n            multiplier: 1.0,\n            jitter: 0.0,\n            max_delay: Duration::from_millis(1),\n        },\n        host: \"localhost\".to_string(),\n        port: 1234,\n    };\n    let dns_client = opts\n        .runtime\n        .get_dns_resolver(rt::ResolverOptions { server_addr: None })\n        .unwrap();\n\n    let mut resolver = DnsResolver::new(dns_client, opts, dns_opts);\n\n    let (update_tx, mut update_rx) = mpsc::unbounded_channel();\n    let mut channel_controller = FakeChannelController {\n        update_tx,\n        update_result: Err(\"test_error\".to_string()),\n    };\n\n    // As the channel returned an error to the resolver, the resolver will\n    // backoff and re-attempt resolution.\n    for _ in 0..5 {\n        work_rx.recv().await.unwrap();\n        resolver.work(&mut channel_controller);\n        let update = update_rx.recv().await.unwrap();\n        assert!(update.endpoints.unwrap().len() > 1);\n    }\n\n    // This time the channel accepts the resolver update.\n    channel_controller.update_result = Ok(());\n    work_rx.recv().await.unwrap();\n    resolver.work(&mut channel_controller);\n    let update = update_rx.recv().await.unwrap();\n    assert!(update.endpoints.unwrap().len() > 1);\n\n    // Since the channel controller returns Ok(), the resolver will stop\n    // producing more updates.\n    tokio::select! {\n        _ = work_rx.recv() => {\n            panic!(\"Received unexpected work request from resolver.\");\n        }\n        _ = tokio::time::sleep(DEFAULT_TEST_SHORT_TIMEOUT) => {\n            println!(\"No event received from resolver.\");\n        }\n    };\n}\n"
  },
  {
    "path": "grpc/src/client/name_resolution/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\n//! Name Resolution for gRPC.\n//!\n//! Name Resolution is the process by which a channel's target is converted into\n//! network addresses (typically IP addresses) used by the channel to connect to\n//! a service.\nuse core::fmt;\nuse std::fmt::Display;\nuse std::fmt::Formatter;\nuse std::hash::Hash;\nuse std::str::FromStr;\nuse std::sync::Arc;\n\nuse url::Url;\n\nuse crate::attributes::Attributes;\nuse crate::byte_str::ByteStr;\nuse crate::client::service_config::ServiceConfig;\nuse crate::rt::GrpcRuntime;\n\nmod backoff;\npub(crate) mod dns;\nmod registry;\npub(crate) use registry::global_registry;\n\n/// Target represents a target for gRPC, as specified in:\n/// https://github.com/grpc/grpc/blob/master/doc/naming.md.\n/// It is parsed from the target string that gets passed during channel creation\n/// by the user. gRPC passes it to the resolver and the balancer.\n///\n/// If the target follows the naming spec, and the parsed scheme is registered\n/// with gRPC, we will parse the target string according to the spec. If the\n/// target does not contain a scheme or if the parsed scheme is not registered\n/// (i.e. no corresponding resolver available to resolve the endpoint), we will\n/// apply the default scheme, and will attempt to reparse it.\n#[derive(Debug, Clone)]\npub(crate) struct Target {\n    url: Url,\n}\n\nimpl FromStr for Target {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s.parse::<Url>() {\n            Ok(url) => Ok(Target { url }),\n            Err(err) => Err(err.to_string()),\n        }\n    }\n}\n\nimpl From<url::Url> for Target {\n    fn from(url: url::Url) -> Self {\n        Target { url }\n    }\n}\n\n/// Target represents a target for gRPC, as specified in:\n/// https://github.com/grpc/grpc/blob/master/doc/naming.md.\n/// It is parsed from the target string that gets passed during channel creation\n/// by the user. gRPC passes it to the resolver and the balancer.\n///\n/// If the target follows the naming spec, and the parsed scheme is registered\n/// with gRPC, we will parse the target string according to the spec. If the\n/// target does not contain a scheme or if the parsed scheme is not registered\n/// (i.e. no corresponding resolver available to resolve the endpoint), we will\n/// apply the default scheme, and will attempt to reparse it.\nimpl Target {\n    pub fn scheme(&self) -> &str {\n        self.url.scheme()\n    }\n\n    /// The host part of the authority.\n    pub fn authority_host(&self) -> &str {\n        self.url.host_str().unwrap_or(\"\")\n    }\n\n    /// The port part of the authority.\n    pub fn authority_port(&self) -> Option<u16> {\n        self.url.port()\n    }\n\n    /// Returns either host:port or host depending on the existence of the port\n    /// in the authority.\n    pub fn authority_host_port(&self) -> String {\n        let host = self.authority_host();\n        let port = self.authority_port();\n        if let Some(port) = port {\n            format!(\"{host}:{port}\")\n        } else {\n            host.to_owned()\n        }\n    }\n\n    /// Retrieves endpoint from `Url.path()`.\n    pub fn path(&self) -> &str {\n        self.url.path()\n    }\n}\n\nimpl Display for Target {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"{}://{}{}\",\n            self.scheme(),\n            self.authority_host_port(),\n            self.path()\n        )\n    }\n}\n\n/// A name resolver factory that produces Resolver instances used by the channel\n/// to resolve network addresses for the target URI.\npub(crate) trait ResolverBuilder: Send + Sync {\n    /// Builds a name resolver instance.\n    ///\n    /// Note that build must not fail.  Instead, an erroring Resolver may be\n    /// returned that calls ChannelController.update() with an Err value.\n    fn build(&self, target: &Target, options: ResolverOptions) -> Box<dyn Resolver>;\n\n    /// Reports the URI scheme handled by this name resolver.\n    fn scheme(&self) -> &str;\n\n    /// Returns the default authority for a channel using this name resolver\n    /// and target. This refers to the *dataplane authority* — the value used\n    /// in the `:authority` header of HTTP/2 requests — and not to be confused\n    /// with the authority portion of the target URI, which typically specifies\n    /// the name of an external server used for name resolution.\n    ///\n    /// By default, this method returns the path portion of the target URI,\n    /// with the leading prefix removed.\n    fn default_authority(&self, target: &Target) -> String {\n        let path = target.path();\n        path.strip_prefix(\"/\").unwrap_or(path).to_string()\n    }\n\n    /// Returns a bool indicating whether the input uri is valid to create a\n    /// resolver.\n    fn is_valid_uri(&self, uri: &Target) -> bool;\n}\n\n/// A collection of data configured on the channel that is constructing this\n/// name resolver.\n#[non_exhaustive]\npub(crate) struct ResolverOptions {\n    /// The authority that will be used for the channel by default. This refers\n    /// to the `:authority` value sent in HTTP/2 requests — the dataplane\n    /// authority — and not the authority portion of the target URI, which is\n    /// typically used to identify the name resolution server.\n    ///\n    /// This value is either the result of the `default_authority` method of\n    /// this `ResolverBuilder`, or another string if the channel was explicitly\n    /// configured to override the default.\n    pub authority: String,\n\n    /// The runtime which provides utilities to do async work.\n    pub runtime: GrpcRuntime,\n\n    /// A hook into the channel's work scheduler that allows the Resolver to\n    /// request the ability to perform operations on the ChannelController.\n    pub work_scheduler: Arc<dyn WorkScheduler>,\n}\n\n/// Used to asynchronously request a call into the Resolver's work method.\npub(crate) trait WorkScheduler: Send + Sync {\n    // Schedules a call into the Resolver's work method.  If there is already a\n    // pending work call that has not yet started, this may not schedule another\n    // call.\n    fn schedule_work(&self);\n}\n\n/// Resolver watches for the updates on the specified target.\n/// Updates include address updates and service config updates.\n// This trait may not need the Sync sub-trait if the channel implementation can\n// ensure that the resolver is accessed serially. The sub-trait can be removed\n// in that case.\npub(crate) trait Resolver: Send + Sync {\n    /// Asks the resolver to obtain an updated resolver result, if applicable.\n    ///\n    /// This is useful for polling resolvers to decide when to re-resolve.\n    /// However, the implementation is not required to re-resolve immediately\n    /// upon receiving this call; it may instead elect to delay based on some\n    /// configured minimum time between queries, to avoid hammering the name\n    /// service with queries.\n    ///\n    /// For watch based resolvers, this may be a no-op.\n    fn resolve_now(&mut self);\n\n    /// Called serially by the channel to provide access to the\n    /// `ChannelController`.\n    fn work(&mut self, channel_controller: &mut dyn ChannelController);\n}\n\n/// The `ChannelController` trait provides the resolver with functionality\n/// to interact with the channel.\npub(crate) trait ChannelController: Send + Sync {\n    /// Notifies the channel about the current state of the name resolver.  If\n    /// an error value is returned, the name resolver should attempt to\n    /// re-resolve, if possible.  The resolver is responsible for applying an\n    /// appropriate backoff mechanism to avoid overloading the system or the\n    /// remote resolver.\n    fn update(&mut self, update: ResolverUpdate) -> Result<(), String>;\n\n    /// Parses the provided JSON service config and returns an instance of a\n    /// ParsedServiceConfig.\n    fn parse_service_config(&self, config: &str) -> Result<ServiceConfig, String>;\n}\n\n#[derive(Clone, Debug)]\n#[non_exhaustive]\n/// ResolverUpdate contains the current Resolver state relevant to the\n/// channel.\npub(crate) struct ResolverUpdate {\n    /// Attributes contains arbitrary data about the resolver intended for\n    /// consumption by the load balancing policy.\n    pub attributes: Attributes,\n\n    /// A list of endpoints which each identify a logical host serving the\n    /// service indicated by the target URI.\n    pub endpoints: Result<Vec<Endpoint>, String>,\n\n    /// The service config which the client should use for communicating with\n    /// the service. If it is None, it indicates no service config is present or\n    /// the resolver does not provide service configs.\n    pub service_config: Result<Option<ServiceConfig>, String>,\n\n    /// An optional human-readable note describing context about the\n    /// resolution, to be passed along to the LB policy for inclusion in\n    /// RPC failure status messages in cases where neither endpoints nor\n    /// service_config has a non-OK status.  For example, a resolver that\n    /// returns an empty endpoint list but a valid service config may set\n    /// to this to something like \"no DNS entries found for <name>\".\n    pub resolution_note: Option<String>,\n}\n\nimpl Default for ResolverUpdate {\n    fn default() -> Self {\n        ResolverUpdate {\n            service_config: Ok(Default::default()),\n            attributes: Default::default(),\n            endpoints: Ok(Default::default()),\n            resolution_note: Default::default(),\n        }\n    }\n}\n\n/// An Endpoint is an address or a collection of addresses which reference one\n/// logical server.  Multiple addresses may be used if there are multiple ways\n/// which the server can be reached, e.g. via IPv4 and IPv6 addresses.\n#[derive(Debug, Default, Clone, PartialEq, Eq)]\n#[non_exhaustive]\npub(crate) struct Endpoint {\n    /// Addresses contains a list of addresses used to access this endpoint.\n    pub addresses: Vec<Address>,\n\n    /// Attributes contains arbitrary data about this endpoint intended for\n    /// consumption by the LB policy.\n    pub attributes: Attributes,\n}\n\nimpl Hash for Endpoint {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.addresses.hash(state);\n    }\n}\n\n/// An Address is an identifier that indicates how to connect to a server.\n#[non_exhaustive]\n#[derive(Debug, Clone, Default, Ord, PartialOrd)]\npub(crate) struct Address {\n    /// The network type is used to identify what kind of transport to create\n    /// when connecting to this address.  Typically TCP_IP_ADDRESS_TYPE.\n    pub network_type: &'static str,\n\n    /// The address itself is passed to the transport in order to create a\n    /// connection to it.\n    pub address: ByteStr,\n\n    /// Attributes contains arbitrary data about this address intended for\n    /// consumption by the subchannel.\n    pub attributes: Attributes,\n}\n\nimpl Eq for Address {}\n\nimpl PartialEq for Address {\n    fn eq(&self, other: &Self) -> bool {\n        self.network_type == other.network_type && self.address == other.address\n    }\n}\n\nimpl Hash for Address {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.network_type.hash(state);\n        self.address.hash(state);\n    }\n}\n\nimpl Display for Address {\n    #[allow(clippy::to_string_in_format_args)]\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}:{}\", self.network_type, self.address.to_string())\n    }\n}\n\n/// Indicates the address is an IPv4 or IPv6 address that should be connected to\n/// via TCP/IP.\npub(crate) static TCP_IP_NETWORK_TYPE: &str = \"tcp\";\n\n// A resolver that returns the same result every time its work method is called.\n// It can be used to return an error to the channel when a resolver fails to\n// build.\nstruct NopResolver {\n    pub update: ResolverUpdate,\n}\n\nimpl Resolver for NopResolver {\n    fn resolve_now(&mut self) {}\n\n    fn work(&mut self, channel_controller: &mut dyn ChannelController) {\n        let _ = channel_controller.update(self.update.clone());\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::Target;\n\n    #[test]\n    pub fn parse_target() {\n        #[derive(Default)]\n        struct TestCase {\n            input: &'static str,\n            want_scheme: &'static str,\n            want_host: &'static str,\n            want_port: Option<u16>,\n            want_host_port: &'static str,\n            want_path: &'static str,\n            want_str: &'static str,\n        }\n        let test_cases = vec![\n            TestCase {\n                input: \"dns:///grpc.io\",\n                want_scheme: \"dns\",\n                want_host_port: \"\",\n                want_host: \"\",\n                want_port: None,\n                want_path: \"/grpc.io\",\n                want_str: \"dns:///grpc.io\",\n            },\n            TestCase {\n                input: \"dns://8.8.8.8:53/grpc.io/docs\",\n                want_scheme: \"dns\",\n                want_host_port: \"8.8.8.8:53\",\n                want_host: \"8.8.8.8\",\n                want_port: Some(53),\n                want_path: \"/grpc.io/docs\",\n                want_str: \"dns://8.8.8.8:53/grpc.io/docs\",\n            },\n            TestCase {\n                input: \"unix:path/to/file\",\n                want_scheme: \"unix\",\n                want_host_port: \"\",\n                want_host: \"\",\n                want_port: None,\n                want_path: \"path/to/file\",\n                want_str: \"unix://path/to/file\",\n            },\n            TestCase {\n                input: \"unix:///run/containerd/containerd.sock\",\n                want_scheme: \"unix\",\n                want_host_port: \"\",\n                want_host: \"\",\n                want_port: None,\n                want_path: \"/run/containerd/containerd.sock\",\n                want_str: \"unix:///run/containerd/containerd.sock\",\n            },\n        ];\n\n        for tc in test_cases {\n            let target: Target = tc.input.parse().unwrap();\n            assert_eq!(target.scheme(), tc.want_scheme);\n            assert_eq!(target.authority_host(), tc.want_host);\n            assert_eq!(target.authority_port(), tc.want_port);\n            assert_eq!(target.authority_host_port(), tc.want_host_port);\n            assert_eq!(target.path(), tc.want_path);\n            assert_eq!(&target.to_string(), tc.want_str);\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/name_resolution/registry.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::collections::HashMap;\nuse std::sync::Arc;\nuse std::sync::Mutex;\nuse std::sync::OnceLock;\n\nuse crate::client::name_resolution::ResolverBuilder;\n\nstatic GLOBAL_RESOLVER_REGISTRY: OnceLock<ResolverRegistry> = OnceLock::new();\n\n/// A registry to store and retrieve name resolvers.  Resolvers are indexed by\n/// the URI scheme they are intended to handle.\n#[derive(Default)]\npub(crate) struct ResolverRegistry {\n    inner: Arc<Mutex<HashMap<String, Arc<dyn ResolverBuilder>>>>,\n}\n\nimpl ResolverRegistry {\n    /// Construct an empty name resolver registry.\n    fn new() -> Self {\n        Self {\n            inner: Arc::default(),\n        }\n    }\n\n    /// Add a name resolver into the registry. builder.scheme() will\n    /// be used as the scheme registered with this builder. If multiple\n    /// resolvers are registered with the same name, the one registered last\n    /// will take effect.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the given scheme contains uppercase characters.\n    pub fn add_builder(&self, builder: Box<dyn ResolverBuilder>) {\n        self.try_add_builder(builder).unwrap();\n    }\n\n    /// Add a name resolver into the registry. builder.scheme() will\n    /// be used as the scheme registered with this builder. If multiple\n    /// resolvers are registered with the same name, the one registered last\n    /// will take effect.\n    pub fn try_add_builder(&self, builder: Box<dyn ResolverBuilder>) -> Result<(), String> {\n        let scheme = builder.scheme();\n        if scheme.chars().any(|c| c.is_ascii_uppercase()) {\n            return Err(format!(\n                \"Scheme must not contain uppercase characters: {scheme}\"\n            ));\n        }\n        self.inner\n            .lock()\n            .unwrap()\n            .insert(scheme.to_string(), Arc::from(builder));\n        Ok(())\n    }\n\n    /// Returns the resolver builder registered for the given scheme, if any.\n    ///\n    /// The provided scheme is case-insensitive; any uppercase characters\n    /// will be converted to lowercase before lookup.\n    pub fn get(&self, scheme: &str) -> Option<Arc<dyn ResolverBuilder>> {\n        self.inner\n            .lock()\n            .unwrap()\n            .get(&scheme.to_lowercase())\n            .cloned()\n    }\n}\n\n/// Global registry for resolver builders.\npub(crate) fn global_registry() -> &'static ResolverRegistry {\n    GLOBAL_RESOLVER_REGISTRY.get_or_init(ResolverRegistry::new)\n}\n"
  },
  {
    "path": "grpc/src/client/service_config.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::any::Any;\nuse std::sync::Arc;\n\n/// An in-memory representation of a service config, usually provided to gRPC as\n/// a JSON object.\n// TODO: this shouldn't be public; users should set with JSON instead.\n#[derive(Debug, Default, Clone)]\npub(crate) struct ServiceConfig {\n    pub load_balancing_policy: Option<LbPolicyType>,\n}\n\n#[derive(Debug, Default, Clone, PartialEq, Eq)]\npub enum LbPolicyType {\n    #[default]\n    PickFirst,\n    RoundRobin,\n}\n\n/// A convenience wrapper for an LB policy's configuration object.\n#[derive(Debug, Clone)]\npub(crate) struct LbConfig {\n    config: Arc<dyn Any + Send + Sync>,\n}\n\nimpl LbConfig {\n    /// Create a new LbConfig wrapper containing the provided config.\n    pub fn new(config: impl Any + Send + Sync) -> Self {\n        LbConfig {\n            config: Arc::new(config),\n        }\n    }\n\n    /// Convenience method to extract the LB policy's configuration object.\n    pub fn convert_to<T: 'static + Send + Sync>(&self) -> Option<Arc<T>> {\n        self.config.clone().downcast::<T>().ok()\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/stream_util.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse crate::Status;\nuse crate::StatusCode;\nuse crate::client::CallOptions;\nuse crate::client::InvokeOnce;\nuse crate::client::RecvStream;\nuse crate::client::interceptor::Intercept;\nuse crate::core::ClientResponseStreamItem;\nuse crate::core::RecvMessage;\nuse crate::core::RequestHeaders;\nuse crate::core::ResponseStreamItem;\nuse crate::core::Trailers;\n\n/// An interceptor that enforces proper gRPC semantics on the response stream.\n#[derive(Clone)]\npub struct ResponseValidator {\n    unary: bool,\n}\n\nimpl ResponseValidator {\n    /// Constructs a new instance of the response validator.  If `unary` is set,\n    /// the validator will enforce proper unary protocol for the stream (e.g.\n    /// exactly one message or an error).\n    ///\n    /// Note that wrapping an entire channel with this interceptor is likely\n    /// inappropraite if `unary` is set.\n    pub fn new(unary: bool) -> Self {\n        Self { unary }\n    }\n}\n\nimpl<I: InvokeOnce> Intercept<I> for ResponseValidator {\n    type SendStream = I::SendStream;\n    type RecvStream = RecvStreamValidator<I::RecvStream>;\n\n    async fn intercept(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n        next: I,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        let (tx, rx) = next.invoke_once(headers, options).await;\n        (tx, RecvStreamValidator::new(rx, self.unary))\n    }\n}\n\n/// RecvStreamValidator wraps a client's RecvStream and enforces proper\n/// RecvStream semantics on it so that protocol validation does not need to be\n/// handled by the consumer.\npub struct RecvStreamValidator<R> {\n    recv_stream: R,\n    state: RecvStreamState,\n    unary_response: bool,\n}\n\nenum RecvStreamState {\n    AwaitingHeaders,\n    AwaitingMessagesOrTrailers,\n    AwaitingTrailers,\n    Done,\n}\n\nimpl<R> RecvStreamValidator<R>\nwhere\n    R: RecvStream,\n{\n    /// Constructs a new `RecvStreamValidator` for converting an untrusted\n    /// `RecvStream` into one that enforces the proper gRPC response stream\n    /// protocol.  If the protocol is violated an error will be synthesized.\n    /// Any calls to the `RecvStream` impl's `next` method beyond `Trailers`\n    /// will not be propagated and will immediately return `StreamClosed`.\n    pub fn new(recv_stream: R, unary_response: bool) -> Self {\n        Self {\n            recv_stream,\n            state: RecvStreamState::AwaitingHeaders,\n            unary_response,\n        }\n    }\n\n    /// Sets the state to Done and produces a synthesized trailer item\n    /// containing the error message.\n    fn error(&mut self, s: impl Into<String>) -> ClientResponseStreamItem {\n        self.state = RecvStreamState::Done;\n        ResponseStreamItem::Trailers(Trailers::new(Status::new(StatusCode::Internal, s)))\n    }\n}\n\nimpl<R> RecvStream for RecvStreamValidator<R>\nwhere\n    R: RecvStream,\n{\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n        // Never call the underlying RecvStream if done.\n        if matches!(self.state, RecvStreamState::Done) {\n            return ResponseStreamItem::StreamClosed;\n        }\n\n        let item = self.recv_stream.next(msg).await;\n\n        match item {\n            ResponseStreamItem::Headers(_) => {\n                if matches!(self.state, RecvStreamState::AwaitingHeaders) {\n                    self.state = RecvStreamState::AwaitingMessagesOrTrailers;\n                    item\n                } else {\n                    self.error(\"stream received multiple headers\")\n                }\n            }\n            ResponseStreamItem::Message(_) => {\n                if matches!(self.state, RecvStreamState::AwaitingMessagesOrTrailers) {\n                    if self.unary_response {\n                        self.state = RecvStreamState::AwaitingTrailers;\n                    }\n                    item\n                } else if matches!(self.state, RecvStreamState::AwaitingTrailers) {\n                    self.error(\"unary stream received multiple messages\")\n                } else {\n                    self.error(\"stream received messages without headers\")\n                }\n            }\n            ResponseStreamItem::Trailers(t) => {\n                if self.unary_response\n                    && !matches!(self.state, RecvStreamState::AwaitingTrailers)\n                    && t.status().code() == StatusCode::Ok\n                {\n                    return self.error(\"unary stream received zero messages\");\n                }\n                // Always return a trailers result immediately - it is valid any\n                // time but sets the stream's state to Done.\n                self.state = RecvStreamState::Done;\n                ResponseStreamItem::Trailers(t)\n            }\n            ResponseStreamItem::StreamClosed => {\n                // Trailers were never received or we would be Done.\n                self.error(\"stream ended without trailers\")\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use std::mem::discriminant;\n    use std::vec;\n\n    use bytes::Buf;\n    use tokio::sync::mpsc::Receiver;\n    use tokio::sync::mpsc::Sender;\n\n    use super::*;\n    use crate::client::SendOptions;\n    use crate::client::SendStream;\n    use crate::client::interceptor::InvokeOnceExt as _;\n    use crate::core::ResponseHeaders;\n    use crate::core::SendMessage;\n\n    // Tests that an error occurs if messages are received before headers.\n    #[tokio::test]\n    async fn test_validator_messages_before_headers() {\n        let scenarios = [vec![ResponseStreamItem::Message(())]];\n\n        for scenario in scenarios {\n            validate_scenario(\n                &scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Internal,\n                    \"received messages without headers\",\n                ))),\n                false,\n            )\n            .await;\n        }\n    }\n\n    // Tests that an error occurs if StreamClosed is received early.\n    #[tokio::test]\n    async fn test_validator_stream_closed_before_trailers() {\n        let scenarios = [\n            vec![ResponseStreamItem::StreamClosed],\n            vec![\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n                ResponseStreamItem::StreamClosed,\n            ],\n            vec![\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n                ResponseStreamItem::Message(()),\n                ResponseStreamItem::StreamClosed,\n            ],\n        ];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Internal,\n                    \"ended without trailers\",\n                ))),\n                false,\n            )\n            .await;\n        }\n    }\n\n    // Tests that an error occurs if headers are received twice.\n    #[tokio::test]\n    async fn test_validator_headers_repeated() {\n        let scenarios = [\n            vec![\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n            ],\n            vec![\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n                ResponseStreamItem::Message(()),\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n            ],\n        ];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Internal,\n                    \"received multiple headers\",\n                ))),\n                false,\n            )\n            .await;\n        }\n    }\n\n    #[tokio::test]\n    async fn test_validator_unary_ok_without_message() {\n        let scenarios = [\n            vec![ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                StatusCode::Ok,\n                \"\",\n            )))],\n            vec![\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(StatusCode::Ok, \"\"))),\n            ],\n        ];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Internal,\n                    \"received zero messages\",\n                ))),\n                true,\n            )\n            .await;\n        }\n    }\n\n    #[tokio::test]\n    async fn test_validator_unary_multiple_messages() {\n        let scenarios = [vec![\n            ResponseStreamItem::Headers(ResponseHeaders::default()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Message(()),\n        ]];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Internal,\n                    \"received multiple messages\",\n                ))),\n                true,\n            )\n            .await;\n        }\n    }\n\n    #[tokio::test]\n    async fn test_validator_successful_stream() {\n        let scenarios = [vec![\n            ResponseStreamItem::Headers(ResponseHeaders::default()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Trailers(Trailers::new(Status::new(StatusCode::Ok, \"\"))),\n        ]];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(StatusCode::Ok, \"\"))),\n                false,\n            )\n            .await;\n        }\n    }\n\n    #[tokio::test]\n    async fn test_validator_erroring_stream() {\n        let scenarios = [vec![\n            ResponseStreamItem::Headers(ResponseHeaders::default()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                StatusCode::Aborted,\n                \"some err\",\n            ))),\n        ]];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Aborted,\n                    \"some err\",\n                ))),\n                false,\n            )\n            .await;\n        }\n    }\n\n    #[tokio::test]\n    async fn test_validator_successful_unary() {\n        let scenarios = [vec![\n            ResponseStreamItem::Headers(ResponseHeaders::default()),\n            ResponseStreamItem::Message(()),\n            ResponseStreamItem::Trailers(Trailers::new(Status::new(StatusCode::Ok, \"\"))),\n        ]];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(StatusCode::Ok, \"\"))),\n                true,\n            )\n            .await;\n        }\n    }\n\n    #[tokio::test]\n    async fn test_validator_erroring_unary() {\n        let scenarios = [\n            vec![ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                StatusCode::Aborted,\n                \"some err\",\n            )))],\n            vec![\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Aborted,\n                    \"some err\",\n                ))),\n            ],\n            vec![\n                ResponseStreamItem::Headers(ResponseHeaders::default()),\n                ResponseStreamItem::Message(()),\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Aborted,\n                    \"some err\",\n                ))),\n            ],\n        ];\n\n        for scenario in &scenarios {\n            validate_scenario(\n                scenario,\n                ResponseStreamItem::Trailers(Trailers::new(Status::new(\n                    StatusCode::Aborted,\n                    \"some err\",\n                ))),\n                true,\n            )\n            .await;\n        }\n    }\n\n    async fn validate_scenario(\n        scenario: &[ResponseStreamItem<()>],\n        expect: ResponseStreamItem<()>,\n        unary: bool,\n    ) {\n        let (channel, tx) = MockRecvStream::new();\n        let channel = channel.with_interceptor(ResponseValidator::new(unary));\n        let (_, recv_stream) = channel\n            .invoke_once(RequestHeaders::default(), CallOptions::default())\n            .await;\n\n        let mut validator = RecvStreamValidator::new(recv_stream, unary);\n        // Send all but the last item, verifying it is returned by the\n        // validator.\n        for item in &scenario[..scenario.len() - 1] {\n            tx.send(item.clone()).await.unwrap();\n            let got = validator.next(&mut NopRecvMessage).await;\n            // Assert that the item sent is the same type as the item received.\n            println!(\"{got:?} vs {item:?}\");\n            assert_eq!(discriminant(&got), discriminant(item));\n        }\n        // Send the final item.\n        tx.send(scenario[scenario.len() - 1].clone()).await.unwrap();\n        let got = validator.next(&mut NopRecvMessage).await;\n        assert!(matches!(&got, expect));\n        if let ResponseStreamItem::Trailers(got_t) = got {\n            let ResponseStreamItem::Trailers(expect_t) = expect else {\n                unreachable!(); // per matches check above\n            };\n            // Assert the codes match.\n            assert_eq!(got_t.status().code(), expect_t.status().code());\n            // Assert the status received contains the expected status error message.\n            assert!(\n                got_t\n                    .status()\n                    .message()\n                    .contains(expect_t.status().message())\n            );\n        }\n    }\n\n    struct NopSendStream;\n\n    impl SendStream for NopSendStream {\n        async fn send(&mut self, _item: &dyn SendMessage, _options: SendOptions) -> Result<(), ()> {\n            Ok(())\n        }\n    }\n\n    struct NopRecvMessage;\n\n    impl RecvMessage for NopRecvMessage {\n        fn decode(&mut self, data: &mut dyn Buf) -> Result<(), String> {\n            Ok(())\n        }\n    }\n\n    /// Implements a RecvStream and an InvokeOnce that can be directed what to\n    /// return manually by writing to the channel returned by `new`.\n    struct MockRecvStream {\n        rx: Receiver<ClientResponseStreamItem>,\n    }\n\n    impl InvokeOnce for MockRecvStream {\n        type SendStream = NopSendStream;\n        type RecvStream = Self;\n\n        async fn invoke_once(\n            self,\n            _headers: RequestHeaders,\n            _options: CallOptions,\n        ) -> (Self::SendStream, Self::RecvStream) {\n            (NopSendStream, self)\n        }\n    }\n\n    impl RecvStream for MockRecvStream {\n        async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n            self.rx.recv().await.unwrap()\n        }\n    }\n\n    impl MockRecvStream {\n        fn new() -> (Self, Sender<ClientResponseStreamItem>) {\n            let (tx, rx) = tokio::sync::mpsc::channel(1);\n            (Self { rx }, tx)\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/subchannel.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse core::panic;\nuse std::collections::BTreeMap;\nuse std::error::Error;\nuse std::fmt::Debug;\nuse std::fmt::Display;\nuse std::sync::Arc;\nuse std::sync::Mutex;\nuse std::sync::RwLock;\nuse std::sync::Weak;\nuse std::time::Duration;\nuse std::time::Instant;\n\nuse tokio::sync::Notify;\nuse tokio::sync::oneshot;\nuse tonic::async_trait;\n\nuse crate::client::CallOptions;\nuse crate::client::ConnectivityState;\nuse crate::client::DynInvoke;\nuse crate::client::DynRecvStream;\nuse crate::client::DynSendStream;\nuse crate::client::channel::InternalChannelController;\nuse crate::client::channel::WorkQueueItem;\nuse crate::client::channel::WorkQueueTx;\nuse crate::client::load_balancing::ExternalSubchannel;\nuse crate::client::load_balancing::SubchannelState;\nuse crate::client::name_resolution::Address;\nuse crate::client::transport::DynTransport;\nuse crate::client::transport::TransportOptions;\nuse crate::core::RequestHeaders;\nuse crate::rt::GrpcRuntime;\n\ntype SharedInvoke = Arc<dyn DynInvoke>;\n\npub trait Backoff: Send + Sync {\n    fn backoff_until(&self) -> Instant;\n    fn reset(&self);\n    fn min_connect_timeout(&self) -> Duration;\n}\n\n// TODO(easwars): Move this somewhere else, where appropriate.\npub(crate) struct NopBackoff {}\nimpl Backoff for NopBackoff {\n    fn backoff_until(&self) -> Instant {\n        Instant::now()\n    }\n    fn reset(&self) {}\n    fn min_connect_timeout(&self) -> Duration {\n        Duration::from_secs(20)\n    }\n}\n\nenum InternalSubchannelState {\n    Idle,\n    Connecting,\n    Ready(Arc<dyn DynInvoke>),\n    TransientFailure(String),\n}\n\nimpl<'a> From<&'a InternalSubchannelState> for SubchannelState {\n    fn from(iss: &'a InternalSubchannelState) -> SubchannelState {\n        match &iss {\n            InternalSubchannelState::Idle => SubchannelState {\n                connectivity_state: ConnectivityState::Idle,\n                last_connection_error: None,\n            },\n            InternalSubchannelState::Connecting => SubchannelState {\n                connectivity_state: ConnectivityState::Connecting,\n                last_connection_error: None,\n            },\n            InternalSubchannelState::Ready(_) => SubchannelState {\n                connectivity_state: ConnectivityState::Ready,\n                last_connection_error: None,\n            },\n            InternalSubchannelState::TransientFailure(err) => {\n                let arc_err: Arc<dyn Error + Send + Sync> = Arc::from(Box::from(err.clone()));\n                SubchannelState {\n                    connectivity_state: ConnectivityState::TransientFailure,\n                    last_connection_error: Some(arc_err),\n                }\n            }\n        }\n    }\n}\n\nimpl Display for InternalSubchannelState {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Idle => write!(f, \"Idle\"),\n            Self::Connecting => write!(f, \"Connecting\"),\n            Self::Ready(_) => write!(f, \"Ready\"),\n            Self::TransientFailure(_) => write!(f, \"TransientFailure\"),\n        }\n    }\n}\n\nimpl Debug for InternalSubchannelState {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Idle => write!(f, \"Idle\"),\n            Self::Connecting => write!(f, \"Connecting\"),\n            Self::Ready(_) => write!(f, \"Ready\"),\n            Self::TransientFailure(_) => write!(f, \"TransientFailure\"),\n        }\n    }\n}\n\nimpl PartialEq for InternalSubchannelState {\n    fn eq(&self, other: &Self) -> bool {\n        match &self {\n            Self::Idle => {\n                if let Self::Idle = other {\n                    return true;\n                }\n            }\n            Self::Connecting => {\n                if let Self::Connecting = other {\n                    return true;\n                }\n            }\n            Self::Ready(_) => {\n                if let Self::Ready(_) = other {\n                    return true;\n                }\n            }\n            Self::TransientFailure(_) => {\n                if let Self::TransientFailure(_) = other {\n                    return true;\n                }\n            }\n        }\n        false\n    }\n}\n\n#[async_trait]\nimpl DynInvoke for InternalSubchannel {\n    async fn dyn_invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Box<dyn DynSendStream>, Box<dyn DynRecvStream>) {\n        let svc = match &self.inner.data.lock().unwrap().state {\n            InternalSubchannelState::Ready(s) => s.clone(),\n            _ => todo!(\"handle non-READY subchannel\"),\n        };\n        svc.dyn_invoke(headers, options).await\n    }\n}\n\npub(crate) struct InternalSubchannel {\n    unregister_fn: Option<Box<dyn FnOnce(SubchannelKey) + Send + Sync>>,\n    key: SubchannelKey,\n    inner: InnerSubchannel,\n    on_drop: Arc<Notify>,\n}\n\n#[derive(Clone)]\nstruct InnerSubchannel {\n    data: Arc<Mutex<SharedInnerSubchannelData>>,\n}\n\nstruct SharedInnerSubchannelData {\n    address: String,\n    state: InternalSubchannelState,\n    watchers: Vec<Arc<SubchannelStateWatcher>>, // TODO(easwars): Revisit the choice for this data structure.\n    on_drop: Arc<Notify>,\n    transport_builder: Arc<dyn DynTransport>,\n    backoff: Arc<dyn Backoff>,\n    runtime: GrpcRuntime,\n    transport_options: TransportOptions,\n}\n\nimpl SharedInnerSubchannelData {\n    fn update_state(&mut self, state: InternalSubchannelState) {\n        self.state = state;\n        let state: SubchannelState = (&self.state).into();\n        for w in &self.watchers {\n            w.on_state_change(state.clone());\n        }\n    }\n}\n\nimpl InternalSubchannel {\n    pub(super) fn new(\n        key: SubchannelKey,\n        transport: Arc<dyn DynTransport>,\n        backoff: Arc<dyn Backoff>,\n        unregister_fn: Box<dyn FnOnce(SubchannelKey) + Send + Sync>,\n        runtime: GrpcRuntime,\n    ) -> Arc<InternalSubchannel> {\n        println!(\"creating new internal subchannel for: {:?}\", &key);\n        let address = key.address.address.to_string();\n        let on_drop = Arc::new(Notify::new());\n        Arc::new(Self {\n            key,\n            on_drop: on_drop.clone(),\n            unregister_fn: Some(unregister_fn),\n            inner: InnerSubchannel {\n                data: Arc::new(Mutex::new(SharedInnerSubchannelData {\n                    address,\n                    transport_builder: transport,\n                    backoff,\n                    runtime,\n                    state: InternalSubchannelState::Idle,\n                    watchers: Vec::new(),\n                    on_drop,\n                    transport_options: TransportOptions::default(), // TODO: should be configurable\n                })),\n            },\n        })\n    }\n\n    pub(super) fn address(&self) -> Address {\n        self.key.address.clone()\n    }\n\n    /// Begins connecting the subchannel asynchronously.  Does nothing if the\n    /// subchannel is not currently idle.\n    pub(super) fn connect(self: &Arc<Self>) {\n        self.inner.begin_connecting();\n    }\n\n    pub(super) fn register_connectivity_state_watcher(&self, watcher: Arc<SubchannelStateWatcher>) {\n        let mut data = self.inner.data.lock().unwrap();\n        data.watchers.push(watcher.clone());\n        let state = (&data.state).into();\n        watcher.on_state_change(state);\n    }\n\n    pub(super) fn unregister_connectivity_state_watcher(\n        &self,\n        watcher: Arc<SubchannelStateWatcher>,\n    ) {\n        self.inner\n            .data\n            .lock()\n            .unwrap()\n            .watchers\n            .retain(|x| !Arc::ptr_eq(x, &watcher));\n    }\n}\n\n// The InnerSubchannel states progress as follows:\n//\n// Idle -> Connecting -> Ready -> Idle [after disconnect]\n// or\n// Idle -> Connecting -> TransientFailure -> Idle [after backoff]\n//\n// Idle is always a terminal state.\nimpl InnerSubchannel {\n    fn move_to_idle(&self) {\n        self.data\n            .lock()\n            .unwrap()\n            .update_state(InternalSubchannelState::Idle);\n    }\n\n    // Starts connecting in the background and manages the full lifecycle of the\n    // subchannel until it returns back to idle in that background task.\n    fn begin_connecting(&self) {\n        let mut data = self.data.lock().unwrap();\n        if data.state != InternalSubchannelState::Idle {\n            return;\n        }\n        data.update_state(InternalSubchannelState::Connecting);\n\n        let self_clone = self.clone();\n        let connect_timeout = data.backoff.min_connect_timeout();\n        let transport_builder = data.transport_builder.clone();\n        let address = data.address.clone();\n        let runtime = data.runtime.clone();\n        let on_drop = data.on_drop.clone();\n        let transport_opts = data.transport_options.clone();\n        data.runtime.spawn(Box::pin(async move {\n            tokio::select! {\n                _ = runtime.sleep(connect_timeout) => {\n                    self_clone.move_to_transient_failure(\"connect timeout expired\".into()).await;\n                }\n                _ = on_drop.notified() => {\n                }\n                result = transport_builder.dyn_connect(address, runtime, &transport_opts) => {\n                    match result {\n                        Ok((service, disconnection_listener)) => {\n                            self_clone.move_to_ready(Arc::from(service), disconnection_listener).await;\n                        }\n                        Err(e) => {\n                            self_clone.move_to_transient_failure(e).await;\n                        }\n                    }\n                },\n            }\n        }));\n    }\n\n    // Sets the state to ready and then waits until the subchannel is dropped or\n    // the connection is lost.  Moves to idle upon connection loss.\n    async fn move_to_ready(\n        &self,\n        svc: Arc<dyn DynInvoke>,\n        closed_rx: oneshot::Receiver<Result<(), String>>,\n    ) {\n        let on_drop;\n        {\n            let mut data = self.data.lock().unwrap();\n            // Reset connection backoff upon successfully moving to ready.\n            data.backoff.reset();\n            on_drop = data.on_drop.clone();\n            data.update_state(InternalSubchannelState::Ready(svc.clone()));\n        }\n        // TODO(easwars): Does it make sense for disconnected() to return an\n        // error string containing information about why the connection\n        // terminated? But what can we do with that error other than logging\n        // it, which the transport can do as well?\n        tokio::select! {\n            _ = on_drop.notified() => {}\n            e = closed_rx => {\n                eprintln!(\"Transport closed: {e:?}\");\n                self.move_to_idle();\n            }\n        }\n    }\n\n    // Sets the state to transient failure and then waits until the subchannel\n    // is dropped or the backoff expires.  Moves to idle upon backoff expiry.\n    async fn move_to_transient_failure(&self, err: String) {\n        let runtime;\n        let on_drop;\n        let backoff_interval;\n        {\n            let mut data = self.data.lock().unwrap();\n            data.update_state(InternalSubchannelState::TransientFailure(err.clone()));\n            backoff_interval = data.backoff.backoff_until();\n            runtime = data.runtime.clone();\n            on_drop = data.on_drop.clone();\n        }\n        tokio::select! {\n            _ = on_drop.notified() => {}\n            _ = runtime.sleep(backoff_interval.saturating_duration_since(Instant::now())) => {\n                self.move_to_idle();\n            }\n        }\n    }\n}\n\nimpl Drop for InternalSubchannel {\n    fn drop(&mut self) {\n        let unregister_fn = self.unregister_fn.take();\n        unregister_fn.unwrap()(self.key.clone());\n        self.on_drop.notify_waiters();\n    }\n}\n\n// SubchannelKey uniiquely identifies a subchannel in the pool.\n#[derive(PartialEq, PartialOrd, Eq, Ord, Clone)]\n\npub(crate) struct SubchannelKey {\n    address: Address,\n}\n\nimpl SubchannelKey {\n    pub(crate) fn new(address: Address) -> Self {\n        Self { address }\n    }\n}\n\nimpl Display for SubchannelKey {\n    #[allow(clippy::to_string_in_format_args)]\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.address.address.to_string())\n    }\n}\n\nimpl Debug for SubchannelKey {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.address)\n    }\n}\n\npub(super) struct InternalSubchannelPool {\n    subchannels: RwLock<BTreeMap<SubchannelKey, Weak<InternalSubchannel>>>,\n}\n\nimpl InternalSubchannelPool {\n    pub(super) fn new() -> Self {\n        Self {\n            subchannels: RwLock::new(BTreeMap::new()),\n        }\n    }\n\n    pub(super) fn lookup_subchannel(&self, key: &SubchannelKey) -> Option<Arc<InternalSubchannel>> {\n        println!(\"looking up subchannel for: {key:?} in the pool\");\n        if let Some(weak_isc) = self.subchannels.read().unwrap().get(key)\n            && let Some(isc) = weak_isc.upgrade()\n        {\n            return Some(isc);\n        }\n        None\n    }\n\n    pub(super) fn register_subchannel(\n        &self,\n        key: &SubchannelKey,\n        isc: Arc<InternalSubchannel>,\n    ) -> Arc<InternalSubchannel> {\n        println!(\"registering subchannel for: {key:?} with the pool\");\n        self.subchannels\n            .write()\n            .unwrap()\n            .insert(key.clone(), Arc::downgrade(&isc));\n        isc\n    }\n\n    pub(super) fn unregister_subchannel(&self, key: &SubchannelKey) {\n        let mut subchannels = self.subchannels.write().unwrap();\n        if let Some(weak_isc) = subchannels.get(key) {\n            if let Some(isc) = weak_isc.upgrade() {\n                return;\n            }\n            println!(\"removing subchannel for: {key:?} from the pool\");\n            subchannels.remove(key);\n            return;\n        }\n        panic!(\"attempt to unregister subchannel for unknown key {:?}\", key);\n    }\n}\n\n#[derive(Clone)]\npub(super) struct SubchannelStateWatcher {\n    subchannel: Weak<ExternalSubchannel>,\n    work_scheduler: WorkQueueTx,\n}\n\nimpl SubchannelStateWatcher {\n    pub(super) fn new(sc: Arc<ExternalSubchannel>, work_scheduler: WorkQueueTx) -> Self {\n        Self {\n            subchannel: Arc::downgrade(&sc),\n            work_scheduler,\n        }\n    }\n\n    fn on_state_change(&self, state: SubchannelState) {\n        // Ignore internal subchannel state changes if the external subchannel\n        // was dropped but its state watcher is still pending unregistration;\n        // such updates are inconsequential.\n        if let Some(sc) = self.subchannel.upgrade() {\n            let _ = self.work_scheduler.send(WorkQueueItem::Closure(Box::new(\n                move |c: &mut InternalChannelController| {\n                    c.lb.clone()\n                        .policy\n                        .lock()\n                        .unwrap()\n                        .as_mut()\n                        .unwrap()\n                        .subchannel_update(sc, &state, c);\n                },\n            )));\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/transport/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::time::Duration;\nuse std::time::Instant;\n\nuse crate::client::DynInvoke;\nuse crate::client::Invoke;\nuse crate::rt::GrpcRuntime;\n\nmod registry;\n\n// Using tower/buffer enables tokio's rt feature even though it's possible to\n// create Buffers with a user provided executor.\n#[cfg(feature = \"_runtime-tokio\")]\nmod tonic;\n\nuse ::tonic::async_trait;\npub(crate) use registry::GLOBAL_TRANSPORT_REGISTRY;\npub(crate) use registry::TransportRegistry;\nuse tokio::sync::oneshot;\n\n// TODO: The following options are specific to HTTP/2. We should\n// instead pass an `Attribute` like struct to the connect method instead which\n// can hold config relevant to a particular transport.\n#[derive(Default, Clone)]\npub(crate) struct TransportOptions {\n    pub(crate) init_stream_window_size: Option<u32>,\n    pub(crate) init_connection_window_size: Option<u32>,\n    pub(crate) http2_keep_alive_interval: Option<Duration>,\n    pub(crate) http2_keep_alive_timeout: Option<Duration>,\n    pub(crate) http2_keep_alive_while_idle: Option<bool>,\n    pub(crate) http2_max_header_list_size: Option<u32>,\n    pub(crate) http2_adaptive_window: Option<bool>,\n    pub(crate) concurrency_limit: Option<usize>,\n    pub(crate) rate_limit: Option<(u64, Duration)>,\n    pub(crate) tcp_keepalive: Option<Duration>,\n    pub(crate) tcp_nodelay: bool,\n    pub(crate) connect_deadline: Option<Instant>,\n}\n\n#[trait_variant::make(Send)]\npub(crate) trait Transport: Sync {\n    type Service: Invoke + 'static;\n\n    async fn connect(\n        &self,\n        address: String,\n        runtime: GrpcRuntime,\n        opts: &TransportOptions,\n    ) -> Result<(Self::Service, oneshot::Receiver<Result<(), String>>), String>;\n}\n\n#[async_trait]\npub(crate) trait DynTransport: Send + Sync {\n    async fn dyn_connect(\n        &self,\n        address: String,\n        runtime: GrpcRuntime,\n        opts: &TransportOptions,\n    ) -> Result<(Box<dyn DynInvoke>, oneshot::Receiver<Result<(), String>>), String>;\n}\n\n#[async_trait]\nimpl<T: Transport> DynTransport for T {\n    async fn dyn_connect(\n        &self,\n        address: String,\n        runtime: GrpcRuntime,\n        opts: &TransportOptions,\n    ) -> Result<(Box<dyn DynInvoke>, oneshot::Receiver<Result<(), String>>), String> {\n        let (i, rx) = self.connect(address, runtime, opts).await?;\n        Ok((Box::new(i), rx))\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/transport/registry.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::collections::HashMap;\nuse std::fmt::Debug;\nuse std::sync::Arc;\nuse std::sync::LazyLock;\nuse std::sync::Mutex;\n\nuse crate::client::transport::DynTransport;\nuse crate::client::transport::Transport;\n\n/// A registry to store and retrieve transports.  Transports are indexed by\n/// the address type they are intended to handle.\n#[derive(Default, Clone)]\npub(crate) struct TransportRegistry {\n    inner: Arc<Mutex<HashMap<String, Arc<dyn DynTransport>>>>,\n}\n\nimpl Debug for TransportRegistry {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let m = self.inner.lock().unwrap();\n        for key in m.keys() {\n            write!(f, \"k: {key:?}\")?\n        }\n        Ok(())\n    }\n}\n\nimpl TransportRegistry {\n    /// Construct an empty name resolver registry.\n    pub(crate) fn new() -> Self {\n        Self::default()\n    }\n\n    pub(crate) fn add_transport<T>(&self, address_type: &str, transport: T)\n    where\n        T: Transport + 'static,\n    {\n        self.inner\n            .lock()\n            .unwrap()\n            .insert(address_type.to_string(), Arc::new(transport));\n    }\n\n    /// Retrieve a name resolver from the registry, or None if not found.\n    pub(crate) fn get_transport(\n        &self,\n        address_type: &str,\n    ) -> Result<Arc<dyn DynTransport>, String> {\n        self.inner\n            .lock()\n            .unwrap()\n            .get(address_type)\n            .ok_or(format!(\n                \"no transport found for address type {address_type}\"\n            ))\n            .cloned()\n    }\n}\n\n/// The registry used if a local registry is not provided to a channel or if it\n/// does not exist in the local registry.\npub(crate) static GLOBAL_TRANSPORT_REGISTRY: LazyLock<TransportRegistry> =\n    LazyLock::new(TransportRegistry::new);\n"
  },
  {
    "path": "grpc/src/client/transport/tonic/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::error::Error;\nuse std::future::Future;\nuse std::net::SocketAddr;\nuse std::pin::Pin;\nuse std::str::FromStr;\nuse std::task::Context;\nuse std::task::Poll;\nuse std::time::Instant;\n\nuse bytes::Buf;\nuse bytes::BufMut as _;\nuse bytes::Bytes;\nuse http::Request as HttpRequest;\nuse http::Response as HttpResponse;\nuse http::Uri;\nuse http::uri::PathAndQuery;\nuse hyper::client::conn::http2::Builder;\nuse hyper::client::conn::http2::SendRequest;\nuse tokio::sync::mpsc;\nuse tokio::sync::oneshot;\nuse tokio_stream::Stream;\nuse tokio_stream::wrappers::ReceiverStream;\nuse tonic::Request as TonicRequest;\nuse tonic::Status as TonicStatus;\nuse tonic::Streaming;\nuse tonic::body::Body;\nuse tonic::client::Grpc;\nuse tonic::client::GrpcService;\nuse tonic::codec::Codec;\nuse tonic::codec::Decoder;\nuse tonic::codec::EncodeBuf;\nuse tonic::codec::Encoder;\nuse tower::ServiceBuilder;\nuse tower::buffer::Buffer;\nuse tower::buffer::future::ResponseFuture as BufferResponseFuture;\nuse tower::limit::ConcurrencyLimitLayer;\nuse tower::limit::RateLimitLayer;\nuse tower::util::BoxService;\nuse tower_service::Service as TowerService;\n\nuse crate::Status;\nuse crate::StatusCode;\nuse crate::client::CallOptions;\nuse crate::client::Invoke;\nuse crate::client::RecvStream;\nuse crate::client::SendOptions;\nuse crate::client::SendStream;\nuse crate::client::name_resolution::TCP_IP_NETWORK_TYPE;\nuse crate::client::transport::Transport;\nuse crate::client::transport::TransportOptions;\nuse crate::client::transport::registry::GLOBAL_TRANSPORT_REGISTRY;\nuse crate::core::ClientResponseStreamItem;\nuse crate::core::RecvMessage;\nuse crate::core::RequestHeaders;\nuse crate::core::ResponseHeaders;\nuse crate::core::SendMessage;\nuse crate::core::Trailers;\nuse crate::rt::BoxedTaskHandle;\nuse crate::rt::GrpcRuntime;\nuse crate::rt::TcpOptions;\nuse crate::rt::hyper_wrapper::HyperCompatExec;\nuse crate::rt::hyper_wrapper::HyperCompatTimer;\nuse crate::rt::hyper_wrapper::HyperStream;\n\n#[cfg(test)]\nmod test;\n\nconst DEFAULT_BUFFER_SIZE: usize = 1024;\npub(crate) type BoxError = Box<dyn Error + Send + Sync>;\n\ntype BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;\ntype BoxStream<T> = Pin<Box<dyn Stream<Item = Result<T, TonicStatus>> + Send>>;\n\npub(crate) fn reg() {\n    GLOBAL_TRANSPORT_REGISTRY.add_transport(TCP_IP_NETWORK_TYPE, TransportBuilder {});\n}\n\nstruct TransportBuilder {}\n\nstruct TonicTransport {\n    grpc: Grpc<TonicService>,\n    task_handle: BoxedTaskHandle,\n    runtime: GrpcRuntime,\n}\n\nimpl Drop for TonicTransport {\n    fn drop(&mut self) {\n        self.task_handle.abort();\n    }\n}\n\nimpl Invoke for TonicTransport {\n    type SendStream = TonicSendStream;\n    type RecvStream = TonicRecvStream;\n\n    async fn invoke(\n        &self,\n        headers: RequestHeaders,\n        options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        let (req_tx, req_rx) = mpsc::channel(1);\n        let request_stream = ReceiverStream::new(req_rx);\n        let mut request = TonicRequest::new(Box::pin(request_stream));\n        let (method, metadata) = headers.into_parts();\n        *request.metadata_mut() = metadata;\n\n        let Ok(path) = PathAndQuery::from_maybe_shared(method) else {\n            return err_streams(Status::new(StatusCode::Internal, \"invalid path\"));\n        };\n\n        let mut grpc = self.grpc.clone();\n        if let Err(e) = grpc.ready().await {\n            return err_streams(Status::new(\n                StatusCode::Unavailable,\n                format!(\"Service was not ready: {e}\"),\n            ));\n        }\n\n        // Note that Tonic's streaming call blocks until the server's headers\n        // are received.  The client needs a SendStream to provide the request\n        // message(s), which the server may be awaiting before sending its\n        // headers.  So, we spawn a task for this period of time, and then we\n        // send the response (headers, stream) to the TonicRecvStream when it is\n        // available.\n        let (resp_tx, resp_rx) = oneshot::channel();\n        self.runtime.spawn(Box::pin(async move {\n            let response = grpc.streaming(request, path, BufCodec {}).await;\n            let _ = resp_tx.send(response);\n        }));\n\n        (\n            TonicSendStream { sender: Ok(req_tx) },\n            TonicRecvStream {\n                state: StreamState::AwaitingHeaders(resp_rx),\n            },\n        )\n    }\n}\n\n// Converts from a tonic status to a trailers stream item.\nfn trailers_from_tonic_status(status: TonicStatus) -> ClientResponseStreamItem {\n    ClientResponseStreamItem::Trailers(Trailers::new(Status::new(\n        StatusCode::from(status.code() as i32),\n        status.message(),\n    )))\n}\n\n// Builds a trailers with a status\nfn trailers_from_status(code: StatusCode, msg: impl Into<String>) -> ClientResponseStreamItem {\n    ClientResponseStreamItem::Trailers(Trailers::new(Status::new(code, msg)))\n}\n\nstruct TonicSendStream {\n    sender: Result<mpsc::Sender<Box<dyn Buf + Send + Sync>>, ()>,\n}\n\nimpl SendStream for TonicSendStream {\n    async fn send(&mut self, msg: &dyn SendMessage, options: SendOptions) -> Result<(), ()> {\n        if let Ok(tx) = &self.sender\n            && let Ok(buf) = msg.encode()\n            && tx.send(buf).await.is_ok()\n        {\n            if options.final_msg {\n                self.sender = Err(());\n            }\n            return Ok(());\n        }\n        Err(())\n    }\n}\n\nstruct TonicRecvStream {\n    state: StreamState,\n}\n\nenum StreamState {\n    Error(Status),\n    AwaitingHeaders(oneshot::Receiver<Result<tonic::Response<Streaming<Bytes>>, TonicStatus>>),\n    Streaming(Streaming<Bytes>),\n    Closed,\n}\n\nimpl RecvStream for TonicRecvStream {\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n        // Take the current state, leaving `Closed` in its place temporarily\n        let state = std::mem::replace(&mut self.state, StreamState::Closed);\n\n        match state {\n            // Closed is terminal.\n            StreamState::Closed => ClientResponseStreamItem::StreamClosed,\n            // Stay closed after sending trailers.\n            StreamState::Error(error) => ClientResponseStreamItem::Trailers(Trailers::new(error)),\n            StreamState::AwaitingHeaders(rx) => match rx.await {\n                Ok(Ok(response)) => {\n                    let (metadata, stream, _extensions) = response.into_parts();\n                    // Start streaming and return the headers.\n                    self.state = StreamState::Streaming(stream);\n                    ClientResponseStreamItem::Headers(\n                        ResponseHeaders::new().with_metadata(metadata),\n                    )\n                }\n                // Stay closed after sending trailers.\n                Err(_) => trailers_from_status(StatusCode::Unknown, \"Task cancelled\"),\n                Ok(Err(status)) => trailers_from_tonic_status(status),\n            },\n            StreamState::Streaming(mut stream) => match stream.message().await {\n                Ok(Some(mut buf)) => match msg.decode(&mut buf) {\n                    Ok(()) => {\n                        // More messages may remain in the stream; set receiver again.\n                        self.state = StreamState::Streaming(stream);\n                        ClientResponseStreamItem::Message(())\n                    }\n                    // TODO: in this case, tonic believes the stream is still\n                    // running, but our decoding failed -- do we need to terminate\n                    // the request stream now even though the Streaming is dropped?\n                    Err(e) => trailers_from_status(\n                        StatusCode::Internal,\n                        format!(\"error decoding response: {e}\"),\n                    ),\n                },\n                // Stay closed after sending trailers.\n                Err(status) => trailers_from_tonic_status(status),\n                Ok(None) => trailers_from_status(StatusCode::Ok, \"\"),\n            },\n        }\n    }\n}\n\nfn err_streams(status: Status) -> (TonicSendStream, TonicRecvStream) {\n    (\n        TonicSendStream { sender: Err(()) },\n        TonicRecvStream {\n            state: StreamState::Error(status),\n        },\n    )\n}\n\nimpl Transport for TransportBuilder {\n    type Service = TonicTransport;\n\n    async fn connect(\n        &self,\n        address: String,\n        runtime: GrpcRuntime,\n        opts: &TransportOptions,\n    ) -> Result<(Self::Service, oneshot::Receiver<Result<(), String>>), String> {\n        let runtime = runtime.clone();\n        let mut settings = Builder::<HyperCompatExec>::new(HyperCompatExec {\n            inner: runtime.clone(),\n        })\n        .timer(HyperCompatTimer {\n            inner: runtime.clone(),\n        })\n        .initial_stream_window_size(opts.init_stream_window_size)\n        .initial_connection_window_size(opts.init_connection_window_size)\n        .keep_alive_interval(opts.http2_keep_alive_interval)\n        .clone();\n\n        if let Some(val) = opts.http2_keep_alive_timeout {\n            settings.keep_alive_timeout(val);\n        }\n\n        if let Some(val) = opts.http2_keep_alive_while_idle {\n            settings.keep_alive_while_idle(val);\n        }\n\n        if let Some(val) = opts.http2_adaptive_window {\n            settings.adaptive_window(val);\n        }\n\n        if let Some(val) = opts.http2_max_header_list_size {\n            settings.max_header_list_size(val);\n        }\n\n        let addr: SocketAddr = SocketAddr::from_str(&address).map_err(|err| err.to_string())?;\n        let tcp_stream_fut = runtime.tcp_stream(\n            addr,\n            TcpOptions {\n                enable_nodelay: opts.tcp_nodelay,\n                keepalive: opts.tcp_keepalive,\n            },\n        );\n        let tcp_stream = if let Some(deadline) = opts.connect_deadline {\n            let timeout = deadline.saturating_duration_since(Instant::now());\n            tokio::select! {\n            _ = runtime.sleep(timeout) => {\n                return Err(\"timed out waiting for TCP stream to connect\".to_string())\n            }\n            tcp_stream = tcp_stream_fut => { tcp_stream? }\n            }\n        } else {\n            tcp_stream_fut.await?\n        };\n        let tcp_stream = HyperStream::new(tcp_stream);\n\n        let (sender, connection) = settings\n            .handshake(tcp_stream)\n            .await\n            .map_err(|err| err.to_string())?;\n        let (tx, rx) = oneshot::channel();\n\n        let task_handle = runtime.spawn(Box::pin(async move {\n            if let Err(err) = connection.await {\n                let _ = tx.send(Err(err.to_string()));\n            } else {\n                let _ = tx.send(Ok(()));\n            }\n        }));\n        let sender = SendRequestWrapper::from(sender);\n\n        let service = ServiceBuilder::new()\n            .option_layer(opts.concurrency_limit.map(ConcurrencyLimitLayer::new))\n            .option_layer(opts.rate_limit.map(|(l, d)| RateLimitLayer::new(l, d)))\n            .map_err(Into::<BoxError>::into)\n            .service(sender);\n\n        let service = BoxService::new(service);\n        let (service, worker) = Buffer::pair(service, DEFAULT_BUFFER_SIZE);\n        runtime.spawn(Box::pin(worker));\n        let uri =\n            Uri::from_maybe_shared(format!(\"http://{}\", &address)).map_err(|e| e.to_string())?; // TODO: err msg\n        let grpc = Grpc::with_origin(TonicService { inner: service }, uri);\n\n        let service = TonicTransport {\n            grpc,\n            task_handle,\n            runtime,\n        };\n        Ok((service, rx))\n    }\n}\n\nstruct SendRequestWrapper {\n    inner: SendRequest<Body>,\n}\n\nimpl From<SendRequest<Body>> for SendRequestWrapper {\n    fn from(inner: SendRequest<Body>) -> Self {\n        Self { inner }\n    }\n}\n\nimpl TowerService<HttpRequest<Body>> for SendRequestWrapper {\n    type Response = HttpResponse<Body>;\n    type Error = BoxError;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: http::Request<Body>) -> Self::Future {\n        let fut = self.inner.send_request(req);\n        Box::pin(async move { fut.await.map_err(Into::into).map(|res| res.map(Body::new)) })\n    }\n}\n\n#[derive(Clone)]\nstruct TonicService {\n    inner: Buffer<http::Request<Body>, BoxFuture<'static, Result<http::Response<Body>, BoxError>>>,\n}\n\nimpl GrpcService<Body> for TonicService {\n    type ResponseBody = Body;\n    type Error = BoxError;\n    type Future = ResponseFuture;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        tower::Service::poll_ready(&mut self.inner, cx)\n    }\n\n    fn call(&mut self, request: http::Request<Body>) -> Self::Future {\n        ResponseFuture {\n            inner: tower::Service::call(&mut self.inner, request),\n        }\n    }\n}\n\n/// A future that resolves to an HTTP response.\n///\n/// This is returned by the `Service::call` on [`Channel`].\npub(crate) struct ResponseFuture {\n    inner: BufferResponseFuture<BoxFuture<'static, Result<HttpResponse<Body>, BoxError>>>,\n}\n\nimpl Future for ResponseFuture {\n    type Output = Result<http::Response<Body>, BoxError>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        Pin::new(&mut self.inner).poll(cx)\n    }\n}\n\npub(crate) struct BufCodec {}\n\nimpl Codec for BufCodec {\n    type Encode = Box<dyn Buf + Send + Sync>;\n    type Decode = Bytes;\n    type Encoder = BufEncoder;\n    type Decoder = BytesDecoder;\n\n    fn encoder(&mut self) -> Self::Encoder {\n        BufEncoder {}\n    }\n\n    fn decoder(&mut self) -> Self::Decoder {\n        BytesDecoder {}\n    }\n}\n\npub struct BytesEncoder {}\n\nimpl Encoder for BytesEncoder {\n    type Item = Bytes;\n    type Error = TonicStatus;\n\n    fn encode(&mut self, item: Self::Item, dst: &mut EncodeBuf<'_>) -> Result<(), Self::Error> {\n        dst.put_slice(&item);\n        Ok(())\n    }\n}\n\npub struct BufEncoder {}\n\nimpl Encoder for BufEncoder {\n    type Item = Box<dyn Buf + Send + Sync>;\n    type Error = TonicStatus;\n\n    fn encode(&mut self, mut item: Self::Item, dst: &mut EncodeBuf<'_>) -> Result<(), Self::Error> {\n        dst.put(&mut *item);\n        Ok(())\n    }\n}\n\n#[derive(Debug)]\npub struct BytesDecoder {}\n\nimpl Decoder for BytesDecoder {\n    type Item = Bytes;\n    type Error = TonicStatus;\n\n    fn decode(\n        &mut self,\n        src: &mut tonic::codec::DecodeBuf<'_>,\n    ) -> Result<Option<Self::Item>, Self::Error> {\n        Ok(Some(src.copy_to_bytes(src.remaining())))\n    }\n}\n"
  },
  {
    "path": "grpc/src/client/transport/tonic/test.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse bytes::Buf;\nuse bytes::Bytes;\nuse tokio::net::TcpListener;\nuse tokio::sync::Notify;\nuse tokio::sync::oneshot;\nuse tokio::time::timeout;\nuse tokio_stream::Stream;\nuse tokio_stream::StreamExt;\nuse tokio_stream::wrappers::ReceiverStream;\nuse tonic::Response;\nuse tonic::Status;\nuse tonic::async_trait;\nuse tonic::transport::Server;\nuse tonic_prost::prost::Message as ProstMessage;\n\nuse crate::client::CallOptions;\nuse crate::client::Channel;\nuse crate::client::Invoke as _;\nuse crate::client::RecvStream as _;\nuse crate::client::SendOptions;\nuse crate::client::SendStream as _;\nuse crate::client::name_resolution::TCP_IP_NETWORK_TYPE;\nuse crate::client::transport::TransportOptions;\nuse crate::client::transport::registry::GLOBAL_TRANSPORT_REGISTRY;\nuse crate::core::ClientResponseStreamItem;\nuse crate::core::RecvMessage;\nuse crate::core::RequestHeaders;\nuse crate::core::SendMessage;\nuse crate::credentials::InsecureChannelCredentials;\nuse crate::echo_pb::EchoRequest;\nuse crate::echo_pb::EchoResponse;\nuse crate::echo_pb::echo_server::Echo;\nuse crate::echo_pb::echo_server::EchoServer;\nuse crate::rt::GrpcRuntime;\nuse crate::rt::tokio::TokioRuntime;\n\nconst DEFAULT_TEST_DURATION: Duration = Duration::from_secs(10);\nconst DEFAULT_TEST_SHORT_DURATION: Duration = Duration::from_millis(10);\n\n// Tests the tonic transport by creating a bi-di stream with a tonic server.\n#[tokio::test]\npub(crate) async fn tonic_transport_rpc() {\n    super::reg();\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap(); // get the assigned address\n    let shutdown_notify = Arc::new(Notify::new());\n    let shutdown_notify_copy = shutdown_notify.clone();\n    println!(\"EchoServer listening on: {addr}\");\n    let server_handle = tokio::spawn(async move {\n        let echo_server = EchoService {};\n        let svc = EchoServer::new(echo_server);\n        let _ = Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(\n                tokio_stream::wrappers::TcpListenerStream::new(listener),\n                shutdown_notify_copy.notified(),\n            )\n            .await;\n    });\n\n    let builder = GLOBAL_TRANSPORT_REGISTRY\n        .get_transport(TCP_IP_NETWORK_TYPE)\n        .unwrap();\n    let config = Arc::new(TransportOptions::default());\n    let (conn, mut disconnection_listener) = builder\n        .dyn_connect(\n            addr.to_string(),\n            GrpcRuntime::new(TokioRuntime::default()),\n            &config,\n        )\n        .await\n        .unwrap();\n\n    let (mut tx, mut rx) = conn\n        .dyn_invoke(\n            RequestHeaders::new()\n                .with_method_name(\"/grpc.examples.echo.Echo/BidirectionalStreamingEcho\"),\n            CallOptions::default(),\n        )\n        .await;\n\n    // Spawn a sender task\n    let client_handle = tokio::spawn(async move {\n        let mut dummy_msg = WrappedEchoResponse(EchoResponse { message: \"\".into() });\n        match rx.next(&mut dummy_msg).await {\n            ClientResponseStreamItem::Headers(_) => {\n                println!(\"Got headers\");\n            }\n            item => panic!(\"Expected headers, got {:?}\", item),\n        }\n\n        for i in 0..5 {\n            let message = format!(\"message {i}\");\n            let request = EchoRequest {\n                message: message.clone(),\n            };\n\n            let req = WrappedEchoRequest(request);\n\n            println!(\"Sent request: {:?}\", req.0);\n            assert!(\n                tx.send(&req, SendOptions::default()).await.is_ok(),\n                \"Receiver dropped\"\n            );\n\n            // Wait for the reply\n            let mut recv_msg = WrappedEchoResponse(EchoResponse { message: \"\".into() });\n            match rx.next(&mut recv_msg).await {\n                ClientResponseStreamItem::Message(()) => {\n                    let echo_response = recv_msg.0;\n                    println!(\"Got response: {echo_response:?}\");\n                    assert_eq!(echo_response.message, message);\n                }\n                item => panic!(\"Expected message, got {:?}\", item),\n            }\n        }\n    });\n\n    client_handle.await.unwrap();\n    // The connection should break only after the server is stopped.\n    assert_eq!(\n        disconnection_listener.try_recv(),\n        Err(oneshot::error::TryRecvError::Empty),\n    );\n    shutdown_notify.notify_waiters();\n    let res = timeout(DEFAULT_TEST_DURATION, disconnection_listener)\n        .await\n        .unwrap()\n        .unwrap();\n    assert_eq!(res, Ok(()));\n    server_handle.await.unwrap();\n}\n\n#[tokio::test]\nasync fn grpc_invoke_tonic_unary() {\n    // Register DNS & Tonic.\n    super::reg();\n    crate::client::name_resolution::dns::reg();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let shutdown_notify = Arc::new(Notify::new());\n    let shutdown_notify_copy = shutdown_notify.clone();\n\n    // Spawn a task for the server.\n    let server_handle = tokio::spawn(async move {\n        let echo_server = EchoService {};\n        let svc = EchoServer::new(echo_server);\n        let _ = Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(\n                tokio_stream::wrappers::TcpListenerStream::new(listener),\n                shutdown_notify_copy.notified(),\n            )\n            .await;\n    });\n\n    // Create the channel.\n    let target = format!(\"dns:///{}\", addr);\n    let channel = Channel::new(\n        &target,\n        InsecureChannelCredentials::new(),\n        Default::default(),\n    );\n\n    // Start the call.\n    let (mut tx, mut rx) = channel\n        .invoke(\n            RequestHeaders::new().with_method_name(\"/grpc.examples.echo.Echo/UnaryEcho\"),\n            CallOptions::default(),\n        )\n        .await;\n\n    // Send the request.\n    let req = WrappedEchoRequest(EchoRequest {\n        message: \"hello interop\".into(),\n    });\n    tx.send(\n        &req,\n        SendOptions {\n            final_msg: true,\n            ..Default::default()\n        },\n    )\n    .await\n    .unwrap();\n\n    // Response should be Headers, Message (\"hello interop\"), Trailers (OK).\n    let mut resp = WrappedEchoResponse(EchoResponse::default());\n\n    let ClientResponseStreamItem::Headers(_) = rx.next(&mut resp).await else {\n        panic!(\"Expected Headers first\");\n    };\n\n    let ClientResponseStreamItem::Message(()) = rx.next(&mut resp).await else {\n        panic!(\"Expected Message after Headers\");\n    };\n    assert_eq!(resp.0.message, \"hello interop\");\n\n    let ClientResponseStreamItem::Trailers(t) = rx.next(&mut resp).await else {\n        panic!(\"Expected Trailers, got StreamClosed or other item\");\n    };\n\n    assert_eq!(\n        t.status().code(),\n        crate::StatusCode::Ok,\n        \"RPC failed: {:?}\",\n        t.status()\n    );\n\n    shutdown_notify.notify_one();\n    server_handle.await.unwrap();\n}\n\nstruct WrappedEchoRequest(EchoRequest);\nstruct WrappedEchoResponse(EchoResponse);\n\nimpl SendMessage for WrappedEchoRequest {\n    fn encode(&self) -> Result<Box<dyn Buf + Send + Sync>, String> {\n        Ok(Box::new(Bytes::from(self.0.encode_to_vec())))\n    }\n}\n\nimpl RecvMessage for WrappedEchoResponse {\n    fn decode(&mut self, data: &mut dyn Buf) -> Result<(), String> {\n        let buf = data.copy_to_bytes(data.remaining());\n        self.0 = EchoResponse::decode(buf).map_err(|e| e.to_string())?;\n        Ok(())\n    }\n}\n\n#[derive(Debug)]\npub(crate) struct EchoService {}\n\n#[async_trait]\nimpl Echo for EchoService {\n    async fn unary_echo(\n        &self,\n        request: tonic::Request<EchoRequest>,\n    ) -> std::result::Result<tonic::Response<EchoResponse>, tonic::Status> {\n        let message = request.into_inner().message;\n        Ok(tonic::Response::new(EchoResponse { message }))\n    }\n\n    type ServerStreamingEchoStream = ReceiverStream<Result<EchoResponse, Status>>;\n\n    async fn server_streaming_echo(\n        &self,\n        _: tonic::Request<EchoRequest>,\n    ) -> std::result::Result<tonic::Response<Self::ServerStreamingEchoStream>, tonic::Status> {\n        unimplemented!()\n    }\n\n    async fn client_streaming_echo(\n        &self,\n        _: tonic::Request<tonic::Streaming<EchoRequest>>,\n    ) -> std::result::Result<tonic::Response<EchoResponse>, tonic::Status> {\n        unimplemented!()\n    }\n    type BidirectionalStreamingEchoStream =\n        Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send + 'static>>;\n\n    async fn bidirectional_streaming_echo(\n        &self,\n        request: tonic::Request<tonic::Streaming<EchoRequest>>,\n    ) -> std::result::Result<tonic::Response<Self::BidirectionalStreamingEchoStream>, tonic::Status>\n    {\n        let mut inbound = request.into_inner();\n\n        // Map each request to a corresponding EchoResponse\n        let outbound = async_stream::try_stream! {\n            while let Some(req) = inbound.next().await {\n                let req = req?; // Return Err(Status) if stream item is error\n                let reply = EchoResponse {\n                    message: req.message.clone(),\n                };\n                yield reply;\n            }\n            println!(\"Server closing stream\");\n        };\n\n        Ok(Response::new(\n            Box::pin(outbound) as Self::BidirectionalStreamingEchoStream\n        ))\n    }\n}\n"
  },
  {
    "path": "grpc/src/core/mod.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\n//! Types used to implement core gRPC functionality common to clients and\n//! servers.  Note that most gRPC applications should not need these types\n//! unless they are implementing custom interceptors.\n\nuse std::any::TypeId;\n\nuse bytes::Buf;\nuse tonic::metadata::MetadataMap;\n\nuse crate::Status;\n\n#[allow(unused)]\npub trait SendMessage: Send + Sync {\n    fn encode(&self) -> Result<Box<dyn Buf + Send + Sync>, String>;\n\n    #[doc(hidden)]\n    unsafe fn _ptr_for(&self, id: TypeId) -> Option<*const ()> {\n        None\n    }\n}\n\n#[allow(unused)]\npub trait RecvMessage: Send + Sync {\n    fn decode(&mut self, data: &mut dyn Buf) -> Result<(), String>;\n\n    #[doc(hidden)]\n    unsafe fn _ptr_for(&mut self, id: TypeId) -> Option<*mut ()> {\n        None\n    }\n}\n\n/// A MessageType describes what underlying message is inside a SendMessage or\n/// RecvMessage so that it can be downcast, e.g. by interceptors.  It allows for\n/// safe downcasting to views containing a lifetime.\npub trait MessageType {\n    /// The message view's type, which may have a lifetime.\n    type Target<'a>;\n}\n\nfn msg_type_id<T: MessageType>() -> TypeId\nwhere\n    T::Target<'static>: 'static,\n{\n    TypeId::of::<T::Target<'static>>()\n}\n\nimpl dyn SendMessage + '_ {\n    /// Downcasts the SendMessage to T::Target if the SendMessage contains a T.\n    pub fn downcast_ref<T: MessageType>(&self) -> Option<&T::Target<'_>>\n    where\n        T::Target<'static>: 'static,\n    {\n        unsafe {\n            if let Some(ptr) = self._ptr_for(msg_type_id::<T>()) {\n                Some(&*(ptr as *mut T::Target<'_>))\n            } else {\n                None\n            }\n        }\n    }\n}\n\n#[allow(unused)]\nimpl dyn RecvMessage + '_ {\n    /// Downcasts the RecvMessage to T::Target if the RecvMessage contains a T.\n    pub fn downcast_mut<T: MessageType>(&mut self) -> Option<&mut T::Target<'_>>\n    where\n        T::Target<'static>: 'static,\n    {\n        unsafe {\n            if let Some(ptr) = self._ptr_for(msg_type_id::<T>()) {\n                Some(&mut *(ptr as *mut T::Target<'_>))\n            } else {\n                None\n            }\n        }\n    }\n}\n\n/// ResponseStreamItem represents an item in a response stream (either server\n/// sending or client receiving).\n///\n/// A response stream must always contain items exactly as follows:\n///\n/// [Headers *Message] Trailers *StreamClosed\n///\n/// That is: optionaly, a Headers value and any number of Message values\n/// (including zero), followed by a required Trailers value.  A response stream\n/// should not be used after Trailers, but reads should return StreamClosed if\n/// it is.\n#[derive(Debug, Clone)]\npub enum ResponseStreamItem<M> {\n    /// Indicates the headers for the stream.\n    Headers(ResponseHeaders),\n    /// Indicates a message on the stream.\n    Message(M),\n    /// Indicates trailers were received on the stream and includes the trailers.\n    Trailers(Trailers),\n    /// Indicates the response stream was closed.  Trailers must have been\n    /// provided before this value may be used.\n    StreamClosed,\n}\n\n/// The client's view of a ResponseStream in a RecvStream: the message type is\n/// void as the received message is passed in via the `next` method.\npub type ClientResponseStreamItem = ResponseStreamItem<()>;\n\n/// The server's view of a ResponseStream in a SendStream: the message type is\n/// part of the payload provided to the `send` method.\npub type ServerResponseStreamItem<'a> = ResponseStreamItem<&'a dyn SendMessage>;\n\n/// Contains all information transmitted in the response headers of an RPC.\n#[derive(Debug, Clone, Default)]\npub struct ResponseHeaders {\n    metadata: MetadataMap,\n}\n\nimpl ResponseHeaders {\n    /// Returns a default ResponseHeaders instance.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Replaces the metadata of self with `metadata`.\n    pub fn with_metadata(mut self, metadata: MetadataMap) -> Self {\n        self.metadata = metadata;\n        self\n    }\n\n    /// Returns a reference to the metadata in these headers.\n    pub fn metadata(&self) -> &MetadataMap {\n        &self.metadata\n    }\n\n    /// Returns a mutable reference to the metadata in these headers.\n    pub fn metadata_mut(&mut self) -> &mut MetadataMap {\n        &mut self.metadata\n    }\n}\n\n/// Contains all information transmitted in the request headers of an RPC.\n#[derive(Debug, Clone, Default)]\npub struct RequestHeaders {\n    /// The full (e.g. \"/Service/Method\") method name specified for the call.\n    method_name: String,\n    /// The application-specified metadata for the call.\n    metadata: MetadataMap,\n}\n\nimpl RequestHeaders {\n    /// Returns a default RequestHeaders instance.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Replaces the method name of self with `method_name`.\n    pub fn with_method_name(mut self, method_name: impl Into<String>) -> Self {\n        self.method_name = method_name.into();\n        self\n    }\n\n    /// Replaces the metadata of self with `metadata`.\n    pub fn with_metadata(mut self, metadata: MetadataMap) -> Self {\n        self.metadata = metadata;\n        self\n    }\n\n    /// Returns the full (e.g. \"/Service/Method\") method name for these headers.\n    pub fn method_name(&self) -> &String {\n        &self.method_name\n    }\n\n    /// Returns a reference to the metadata in these headers.\n    pub fn metadata(&self) -> &MetadataMap {\n        &self.metadata\n    }\n\n    /// Returns a mutable reference to the metadata in these headers.\n    pub fn metadata_mut(&mut self) -> &mut MetadataMap {\n        &mut self.metadata\n    }\n\n    /// Returns the owned fields in the RequestHeaders.\n    // TODO: make public once fields are fixed.\n    pub(crate) fn into_parts(self) -> (String, MetadataMap) {\n        (self.method_name, self.metadata)\n    }\n}\n\n/// Contains all information transmitted in the response trailers of an RPC.\n/// gRPC does not support request trailers.\n#[derive(Debug, Clone)]\npub struct Trailers {\n    status: Status,\n    metadata: MetadataMap,\n}\n\nimpl Trailers {\n    /// Returns a default RequestHeaders instance.\n    pub fn new(status: Status) -> Self {\n        Self {\n            status,\n            metadata: MetadataMap::default(),\n        }\n    }\n\n    /// Replaces the status of self with `status`.\n    pub fn with_status(mut self, status: Status) -> Self {\n        self.status = status;\n        self\n    }\n\n    /// Returns a reference to the status contained in these trailers.\n    pub fn status(&self) -> &Status {\n        &self.status\n    }\n\n    /// Replaces the metadata of self with `metadata`.\n    pub fn with_metadata(mut self, metadata: MetadataMap) -> Self {\n        self.metadata = metadata;\n        self\n    }\n\n    /// Returns a mutable reference to the metadata in these trailers.\n    pub fn metadata_mut(&mut self) -> &mut MetadataMap {\n        &mut self.metadata\n    }\n\n    /// Returns a reference to the metadata in these trailers.\n    pub fn metadata(&self) -> &MetadataMap {\n        &self.metadata\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/call.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::fmt::Debug;\nuse std::sync::Arc;\n\nuse tonic::Status;\nuse tonic::async_trait;\nuse tonic::metadata::MetadataMap;\n\nuse crate::attributes::Attributes;\nuse crate::credentials::SecurityLevel;\n\n/// Details regarding the call.\n///\n/// The fully qualified method name is constructed as:\n/// `service_url` + \"/\" + `method_name`\npub struct CallDetails {\n    service_url: String,\n    method_name: String,\n}\n\nimpl CallDetails {\n    pub(crate) fn new(service_url: String, method_name: String) -> Self {\n        Self {\n            service_url,\n            method_name,\n        }\n    }\n\n    /// Returns the base URL of the service for this call.\n    pub fn service_url(&self) -> &str {\n        &self.service_url\n    }\n\n    /// The method name suffix (e.g., `Method` in `package.Service/Method`).\n    pub fn method_name(&self) -> &str {\n        &self.method_name\n    }\n}\n\npub struct ChannelSecurityInfo {\n    security_protocol: &'static str,\n    security_level: SecurityLevel,\n    /// Stores extra data derived from the underlying protocol.\n    attributes: Attributes,\n}\n\nimpl ChannelSecurityInfo {\n    pub(crate) fn new(\n        security_protocol: &'static str,\n        security_level: SecurityLevel,\n        attributes: Attributes,\n    ) -> Self {\n        Self {\n            security_protocol,\n            security_level,\n            attributes,\n        }\n    }\n\n    pub fn security_protocol(&self) -> &'static str {\n        self.security_protocol\n    }\n\n    pub fn security_level(&self) -> SecurityLevel {\n        self.security_level\n    }\n\n    pub fn attributes(&self) -> &Attributes {\n        &self.attributes\n    }\n}\n\n/// Defines the interface for credentials that need to attach security\n/// information to every individual RPC (e.g., OAuth2 tokens, JWTs).\n#[async_trait]\npub trait CallCredentials: Send + Sync + Debug {\n    /// Generates the authentication metadata for a specific call.\n    ///\n    /// This method is called by the transport layer on each request.\n    /// Implementations should populate the provided `metadata` map with the\n    /// necessary authorization headers (e.g., `authorization: Bearer <token>`).\n    ///\n    /// If this returns an `Err`, the RPC will fail immediately with a status\n    /// derived from the error if the status code is in the range defined in\n    /// gRFC A54. Otherwise, the RPC is failed with an internal status.\n    ///\n    /// # Cancellation Safety\n    ///\n    /// Implementations of this method must be cancel safe as the future may be\n    /// dropped due to RPC timeouts.\n    async fn get_metadata(\n        &self,\n        call_details: &CallDetails,\n        auth_info: &ChannelSecurityInfo,\n        metadata: &mut MetadataMap,\n    ) -> Result<(), Status>;\n\n    /// Indicates the minimum transport security level required to send\n    /// these credentials.\n    /// **Default:** Returns [`SecurityLevel::PrivacyAndIntegrity`].\n    fn minimum_channel_security_level(&self) -> SecurityLevel {\n        SecurityLevel::PrivacyAndIntegrity\n    }\n}\n\n/// A composite implementation of [`CallCredentials`] that combines\n/// multiple credentials.\n///\n/// The inner credentials are invoked sequentially during metadata retrieval.\n#[derive(Debug)]\npub struct CompositeCallCredentials {\n    creds: Vec<Arc<dyn CallCredentials>>,\n}\n\nimpl CompositeCallCredentials {\n    /// Creates a new [`CompositeCallCredentials`] with the first two credentials.\n    pub fn new(first: Arc<dyn CallCredentials>, second: Arc<dyn CallCredentials>) -> Self {\n        Self {\n            creds: vec![first, second],\n        }\n    }\n\n    /// Adds an additional [`CallCredentials`] to the composite.\n    pub fn with_call_credentials(mut self, creds: Arc<dyn CallCredentials>) -> Self {\n        self.creds.push(creds);\n        self\n    }\n}\n\n#[async_trait]\nimpl CallCredentials for CompositeCallCredentials {\n    async fn get_metadata(\n        &self,\n        call_details: &CallDetails,\n        auth_info: &ChannelSecurityInfo,\n        metadata: &mut MetadataMap,\n    ) -> Result<(), Status> {\n        for cred in &self.creds {\n            cred.get_metadata(call_details, auth_info, metadata).await?;\n        }\n        Ok(())\n    }\n\n    fn minimum_channel_security_level(&self) -> SecurityLevel {\n        self.creds\n            .iter()\n            .map(|c| c.minimum_channel_security_level())\n            .max()\n            .expect(\"CompositeCallCredentials must hold at least two children.\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use tonic::metadata::MetadataValue;\n\n    use super::*;\n\n    #[derive(Debug)]\n    struct MockCallCredentials {\n        key: String,\n        value: String,\n        security_level: SecurityLevel,\n    }\n\n    #[async_trait]\n    impl CallCredentials for MockCallCredentials {\n        async fn get_metadata(\n            &self,\n            _call_details: &CallDetails,\n            _auth_info: &ChannelSecurityInfo,\n            metadata: &mut MetadataMap,\n        ) -> Result<(), Status> {\n            metadata.insert(\n                self.key\n                    .parse::<tonic::metadata::MetadataKey<tonic::metadata::Ascii>>()\n                    .unwrap(),\n                MetadataValue::try_from(&self.value).unwrap(),\n            );\n            Ok(())\n        }\n\n        fn minimum_channel_security_level(&self) -> SecurityLevel {\n            self.security_level\n        }\n    }\n\n    #[tokio::test]\n    async fn test_composite_call_credentials() {\n        let cred1 = Arc::new(MockCallCredentials {\n            key: \"key1\".to_string(),\n            value: \"value1\".to_string(),\n            security_level: SecurityLevel::IntegrityOnly,\n        });\n        let cred2 = Arc::new(MockCallCredentials {\n            key: \"key2\".to_string(),\n            value: \"value2\".to_string(),\n            security_level: SecurityLevel::PrivacyAndIntegrity,\n        });\n\n        let composite = CompositeCallCredentials::new(cred1, cred2);\n\n        let call_details = CallDetails {\n            service_url: \"url\".to_string(),\n            method_name: \"method\".to_string(),\n        };\n        let auth_info = ChannelSecurityInfo::new(\n            \"test\",\n            SecurityLevel::PrivacyAndIntegrity,\n            Attributes::new(),\n        );\n        let mut metadata = MetadataMap::new();\n\n        composite\n            .get_metadata(&call_details, &auth_info, &mut metadata)\n            .await\n            .unwrap();\n\n        assert_eq!(metadata.get(\"key1\").unwrap(), \"value1\");\n        assert_eq!(metadata.get(\"key2\").unwrap(), \"value2\");\n        assert_eq!(\n            composite.minimum_channel_security_level(),\n            SecurityLevel::PrivacyAndIntegrity\n        );\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/client.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::sync::Arc;\n\nuse crate::attributes::Attributes;\nuse crate::credentials::ChannelCredentials;\nuse crate::credentials::ProtocolInfo;\nuse crate::credentials::SecurityLevel;\nuse crate::credentials::call::CallCredentials;\nuse crate::credentials::call::CompositeCallCredentials;\nuse crate::credentials::common::Authority;\nuse crate::credentials::insecure;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\n\n#[trait_variant::make(Send)]\npub trait ChannelCredsInternal {\n    type ContextType: ClientConnectionSecurityContext;\n    type Output<I>;\n    /// Performs the client-side authentication handshake on a raw endpoint.\n    ///\n    /// This method wraps the provided `source` endpoint with the security protocol\n    /// (e.g., TLS) and returns the authenticated endpoint along with its\n    /// security details.\n    ///\n    /// # Arguments\n    ///\n    /// * `authority` - The `:authority` header value to be used when creating\n    ///   new streams.\n    ///   **Important:** Implementations must use this value as the server name\n    ///   (e.g., for SNI) during the handshake.\n    /// * `source` - The raw connection handle.\n    /// * `info` - Additional context passed from the resolver or load balancer.\n    async fn connect<Input: GrpcEndpoint>(\n        &self,\n        authority: &Authority,\n        source: Input,\n        info: ClientHandshakeInfo,\n        runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<Self::Output<Input>, Self::ContextType>, String>;\n\n    /// Returns call credentials to be used for all RPCs made on a connection.\n    fn get_call_credentials(&self) -> Option<&Arc<dyn CallCredentials>>;\n}\n\npub struct HandshakeOutput<T, C: ClientConnectionSecurityContext> {\n    pub endpoint: T,\n    pub security: ClientConnectionSecurityInfo<C>,\n}\n\npub trait ClientConnectionSecurityContext: Send + Sync + 'static {\n    /// Checks if the established connection is authorized to send requests to\n    /// the given authority.\n    ///\n    /// This is primarily used for HTTP/2 connection reuse (coalescing). If the\n    /// underlying security handshake (e.g., a TLS certificate) covers the provided\n    /// `authority`, the existing connection may be reused for that host.\n    ///\n    /// # Returns\n    ///\n    /// * `true` - The connection is valid for this authority.\n    /// * `false` - The connection cannot be reused; a new connection must be created.\n    fn validate_authority(&self, authority: &Authority) -> bool {\n        false\n    }\n}\n\nimpl ClientConnectionSecurityContext for Box<dyn ClientConnectionSecurityContext> {\n    fn validate_authority(&self, authority: &Authority) -> bool {\n        (**self).validate_authority(authority)\n    }\n}\n\n/// Represents the security state of an established client-side connection.\npub struct ClientConnectionSecurityInfo<C> {\n    security_protocol: &'static str,\n    security_level: SecurityLevel,\n    security_context: C,\n    /// Stores extra data derived from the underlying protocol.\n    attributes: Attributes,\n}\n\nimpl<C> ClientConnectionSecurityInfo<C> {\n    pub fn new(\n        security_protocol: &'static str,\n        security_level: SecurityLevel,\n        security_context: C,\n        attributes: Attributes,\n    ) -> Self {\n        Self {\n            security_protocol,\n            security_level,\n            security_context,\n            attributes,\n        }\n    }\n\n    pub fn security_protocol(&self) -> &'static str {\n        self.security_protocol\n    }\n\n    pub fn security_level(&self) -> SecurityLevel {\n        self.security_level\n    }\n\n    pub fn security_context(&self) -> &C {\n        &self.security_context\n    }\n\n    pub fn attributes(&self) -> &Attributes {\n        &self.attributes\n    }\n\n    pub fn into_boxed(\n        self,\n    ) -> ClientConnectionSecurityInfo<Box<dyn ClientConnectionSecurityContext>>\n    where\n        C: ClientConnectionSecurityContext + 'static,\n    {\n        ClientConnectionSecurityInfo {\n            security_protocol: self.security_protocol,\n            security_level: self.security_level,\n            security_context: Box::new(self.security_context),\n            attributes: self.attributes,\n        }\n    }\n}\n\n/// Holds data to be passed during the connection handshake.\n///\n/// This mechanism allows arbitrary data to flow from gRPC core components—such\n/// as resolvers and load balancers—down to the credential implementations.\n///\n/// Individual credential implementations are responsible for validating and\n/// interpreting the format of the data they receive.\n#[derive(Default)]\npub struct ClientHandshakeInfo {\n    /// The bag of attributes containing the handshake data.\n    attributes: Attributes,\n}\n\nimpl ClientHandshakeInfo {\n    pub fn new(attributes: Attributes) -> Self {\n        Self { attributes }\n    }\n\n    pub fn attributes(&self) -> &Attributes {\n        &self.attributes\n    }\n}\n\n/// A credential that combines [`ChannelCredentials`] with [`CallCredentials`].\n///\n/// This is used to attach per-call authentication (like OAuth2 tokens) to a\n/// secure channel (like TLS).\npub struct CompositeChannelCredentials<T> {\n    channel_creds: T,\n    call_creds: Arc<dyn CallCredentials>,\n}\n\nimpl<T: ChannelCredentials> CompositeChannelCredentials<T> {\n    pub fn new(channel_creds: T, call_creds: Arc<dyn CallCredentials>) -> Result<Self, String> {\n        if channel_creds.info().security_protocol() == insecure::PROTOCOL_NAME {\n            return Err(\"using tokens on an insecure credentials is disallowed\".to_string());\n        }\n\n        let combined_call_creds = if let Some(existing) = channel_creds.get_call_credentials() {\n            let composite_creds = CompositeCallCredentials::new(existing.clone(), call_creds);\n            Arc::new(composite_creds)\n        } else {\n            call_creds\n        };\n\n        Ok(Self {\n            channel_creds,\n            call_creds: combined_call_creds,\n        })\n    }\n}\n\nimpl<T: ChannelCredentials> ChannelCredsInternal for CompositeChannelCredentials<T> {\n    type ContextType = T::ContextType;\n    type Output<I> = T::Output<I>;\n\n    async fn connect<Input: GrpcEndpoint>(\n        &self,\n        authority: &Authority,\n        source: Input,\n        info: ClientHandshakeInfo,\n        runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<Self::Output<Input>, Self::ContextType>, String> {\n        self.channel_creds\n            .connect(authority, source, info, runtime)\n            .await\n    }\n\n    fn get_call_credentials(&self) -> Option<&Arc<dyn CallCredentials>> {\n        Some(&self.call_creds)\n    }\n}\n\nimpl<T: ChannelCredentials> ChannelCredentials for CompositeChannelCredentials<T> {\n    fn info(&self) -> &ProtocolInfo {\n        self.channel_creds.info()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use tokio::net::TcpListener;\n    use tonic::Status;\n    use tonic::async_trait;\n    use tonic::metadata::MetadataMap;\n    use tonic::metadata::MetadataValue;\n\n    use super::*;\n    use crate::credentials::call::CallCredentials;\n    use crate::credentials::call::CallDetails;\n    use crate::credentials::call::ChannelSecurityInfo;\n    use crate::credentials::insecure::InsecureChannelCredentials;\n    use crate::credentials::local::LocalChannelCredentials;\n    use crate::rt;\n    use crate::rt::TcpOptions;\n\n    #[derive(Debug)]\n    struct MockCallCredentials {\n        key: &'static str,\n        value: &'static str,\n        min_security_level: SecurityLevel,\n    }\n\n    #[async_trait]\n    impl CallCredentials for MockCallCredentials {\n        async fn get_metadata(\n            &self,\n            _call_details: &CallDetails,\n            _auth_info: &ChannelSecurityInfo,\n            metadata: &mut MetadataMap,\n        ) -> Result<(), Status> {\n            metadata.insert(\n                self.key\n                    .parse::<tonic::metadata::MetadataKey<tonic::metadata::Ascii>>()\n                    .unwrap(),\n                MetadataValue::try_from(self.value).unwrap(),\n            );\n            Ok(())\n        }\n\n        fn minimum_channel_security_level(&self) -> SecurityLevel {\n            self.min_security_level\n        }\n    }\n\n    #[tokio::test]\n    async fn test_multiple_composition() {\n        let channel_creds = LocalChannelCredentials::new();\n        let call_creds1 = Arc::new(MockCallCredentials {\n            key: \"auth1\",\n            value: \"val1\",\n            min_security_level: SecurityLevel::IntegrityOnly,\n        });\n        let call_creds2 = Arc::new(MockCallCredentials {\n            key: \"auth2\",\n            value: \"val2\",\n            min_security_level: SecurityLevel::PrivacyAndIntegrity,\n        });\n\n        // First composition.\n        let composite1 = CompositeChannelCredentials::new(channel_creds, call_creds1).unwrap();\n\n        // Second composition (using the first composite as base).\n        let composite2 = CompositeChannelCredentials::new(composite1, call_creds2).unwrap();\n\n        // Verify call credentials\n        let combined_call_creds = composite2.get_call_credentials().unwrap();\n        let call_details = CallDetails::new(\"service\".to_string(), \"method\".to_string());\n        let auth_info =\n            ChannelSecurityInfo::new(\"local\", SecurityLevel::NoSecurity, Attributes::new());\n        let mut metadata = MetadataMap::new();\n\n        combined_call_creds\n            .get_metadata(&call_details, &auth_info, &mut metadata)\n            .await\n            .unwrap();\n\n        assert_eq!(metadata.get(\"auth1\").unwrap(), \"val1\");\n        assert_eq!(metadata.get(\"auth2\").unwrap(), \"val2\");\n\n        // Verify min security level is the max of both.\n        assert_eq!(\n            combined_call_creds.minimum_channel_security_level(),\n            SecurityLevel::PrivacyAndIntegrity\n        );\n\n        // Verify security level\n        let addr = \"127.0.0.1:0\";\n        let listener = TcpListener::bind(addr).await.unwrap();\n        let server_addr = listener.local_addr().unwrap();\n        let authority = Authority::new(\"localhost\".to_string(), Some(server_addr.port()));\n        let runtime = rt::default_runtime();\n        let endpoint = runtime\n            .tcp_stream(server_addr, TcpOptions::default())\n            .await\n            .unwrap();\n\n        let output = composite2\n            .connect(\n                &authority,\n                endpoint,\n                ClientHandshakeInfo::default(),\n                runtime,\n            )\n            .await\n            .unwrap();\n        assert_eq!(output.security.security_level(), SecurityLevel::NoSecurity);\n        assert_eq!(output.security.security_protocol(), \"local\");\n    }\n\n    #[test]\n    fn test_composite_channel_credentials_insecure() {\n        let channel_creds = InsecureChannelCredentials::new();\n        let call_creds = Arc::new(MockCallCredentials {\n            key: \"auth\",\n            value: \"val\",\n            min_security_level: SecurityLevel::NoSecurity,\n        });\n        let result = CompositeChannelCredentials::new(channel_creds, call_creds);\n        assert!(result.is_err());\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/dyn_wrapper.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse tonic::async_trait;\n\nuse crate::credentials::ChannelCredentials;\nuse crate::credentials::ProtocolInfo;\nuse crate::credentials::ServerCredentials;\nuse crate::credentials::client::ClientConnectionSecurityContext;\nuse crate::credentials::client::ClientHandshakeInfo;\nuse crate::credentials::client::HandshakeOutput;\nuse crate::credentials::common::Authority;\nuse crate::credentials::server::HandshakeOutput as ServerHandshakeOutput;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\nuse crate::send_future::SendFuture;\n\ntype BoxEndpoint = Box<dyn GrpcEndpoint>;\n\n// Bridge trait for type erasure.\n#[async_trait]\npub(crate) trait DynChannelCredentials: Send + Sync {\n    async fn connect(\n        &self,\n        authority: &Authority,\n        source: BoxEndpoint,\n        info: ClientHandshakeInfo,\n        runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<BoxEndpoint, Box<dyn ClientConnectionSecurityContext>>, String>;\n\n    fn info(&self) -> &ProtocolInfo;\n}\n\n#[async_trait]\nimpl<T> DynChannelCredentials for T\nwhere\n    T: ChannelCredentials,\n    T::Output<BoxEndpoint>: GrpcEndpoint,\n{\n    async fn connect(\n        &self,\n        authority: &Authority,\n        source: BoxEndpoint,\n        info: ClientHandshakeInfo,\n        runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<BoxEndpoint, Box<dyn ClientConnectionSecurityContext>>, String>\n    {\n        let output = self\n            .connect(authority, source, info, runtime)\n            .make_send()\n            .await?;\n\n        let stream = output.endpoint;\n        let sec_info = output.security;\n\n        Ok(HandshakeOutput {\n            endpoint: Box::new(stream),\n            security: sec_info.into_boxed(),\n        })\n    }\n\n    fn info(&self) -> &ProtocolInfo {\n        self.info()\n    }\n}\n\n// Bridge trait for type erasure.\n#[async_trait]\npub(crate) trait DynServerCredentials: Send + Sync {\n    async fn accept(\n        &self,\n        source: BoxEndpoint,\n        runtime: GrpcRuntime,\n    ) -> Result<ServerHandshakeOutput<BoxEndpoint>, String>;\n\n    fn info(&self) -> &ProtocolInfo;\n}\n\n#[async_trait]\nimpl<T> DynServerCredentials for T\nwhere\n    T: ServerCredentials,\n    T::Output<BoxEndpoint>: GrpcEndpoint,\n{\n    async fn accept(\n        &self,\n        source: BoxEndpoint,\n        runtime: GrpcRuntime,\n    ) -> Result<ServerHandshakeOutput<BoxEndpoint>, String> {\n        let output = SendFuture::make_send(self.accept(source, runtime)).await?;\n        Ok(ServerHandshakeOutput {\n            endpoint: Box::new(output.endpoint),\n            security: output.security,\n        })\n    }\n\n    fn info(&self) -> &ProtocolInfo {\n        self.info()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use tokio::io::AsyncReadExt;\n    use tokio::io::AsyncWriteExt;\n    use tokio::net::TcpListener;\n\n    use super::*;\n    use crate::credentials::InsecureServerCredentials;\n    use crate::credentials::SecurityLevel;\n    use crate::credentials::client::ClientHandshakeInfo;\n    use crate::credentials::common::Authority;\n    use crate::credentials::insecure::InsecureChannelCredentials;\n    use crate::rt::TcpOptions;\n    use crate::rt::{self};\n\n    #[tokio::test]\n    async fn test_dyn_client_credential_dispatch() {\n        let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n        let addr = listener.local_addr().unwrap();\n\n        let creds = InsecureChannelCredentials::new();\n        let dyn_creds: Box<dyn DynChannelCredentials> = Box::new(creds);\n\n        let authority = Authority::new(\"localhost\".to_string(), Some(addr.port()));\n\n        let runtime = crate::rt::default_runtime();\n        let source = runtime\n            .tcp_stream(addr, TcpOptions::default())\n            .await\n            .unwrap();\n        let info = ClientHandshakeInfo::default();\n\n        let result = dyn_creds.connect(&authority, source, info, runtime).await;\n\n        assert!(result.is_ok());\n        let output = result.unwrap();\n        let mut endpoint = output.endpoint;\n        let security_info = output.security;\n\n        assert!(!endpoint.get_local_address().is_empty());\n        assert_eq!(security_info.security_protocol(), \"insecure\");\n        assert_eq!(security_info.security_level(), SecurityLevel::NoSecurity);\n\n        // Verify data transfer.\n        let (mut server_stream, _) = listener.accept().await.unwrap();\n        assert_eq!(\n            endpoint.get_local_address(),\n            &server_stream.peer_addr().unwrap().to_string()\n        );\n        let test_data = b\"hello dynamic grpc\";\n        server_stream.write_all(test_data).await.unwrap();\n\n        let mut buf = vec![0u8; test_data.len()];\n        endpoint.read_exact(&mut buf).await.unwrap();\n        assert_eq!(buf, test_data);\n\n        // Validate arbitrary authority.\n        assert!(\n            security_info\n                .security_context()\n                .validate_authority(&authority)\n        );\n    }\n\n    #[tokio::test]\n    async fn test_dyn_server_credential_dispatch() {\n        let creds = InsecureServerCredentials::new();\n        let dyn_creds: Box<dyn DynServerCredentials> = Box::new(creds);\n\n        let info = dyn_creds.info();\n        assert_eq!(info.security_protocol, \"insecure\");\n\n        let addr = \"127.0.0.1:0\";\n        let runtime = rt::default_runtime();\n        let mut listener = runtime\n            .listen_tcp(addr.parse().unwrap(), TcpOptions::default())\n            .await\n            .unwrap();\n        let server_addr = *listener.local_addr();\n\n        let client_handle = tokio::spawn(async move {\n            let mut stream = tokio::net::TcpStream::connect(server_addr).await.unwrap();\n            let data = b\"hello dynamic grpc server\";\n            stream.write_all(data).await.unwrap();\n\n            // Keep the connection alive for a bit so server can read\n            let mut buf = vec![0u8; 1];\n            let _ = stream.read(&mut buf).await;\n        });\n\n        let (server_stream, _) = listener.accept().await.unwrap();\n\n        let result = dyn_creds.accept(server_stream, runtime).await;\n\n        assert!(result.is_ok());\n        let output = result.unwrap();\n        let mut endpoint = output.endpoint;\n        let security_info = output.security;\n\n        assert_eq!(security_info.security_protocol(), \"insecure\");\n        assert_eq!(security_info.security_level(), SecurityLevel::NoSecurity);\n\n        let mut buf = vec![0u8; 25];\n        endpoint.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf[..], b\"hello dynamic grpc server\");\n\n        client_handle.abort();\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/insecure.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::sync::Arc;\n\nuse crate::attributes::Attributes;\nuse crate::credentials::ChannelCredentials;\nuse crate::credentials::ProtocolInfo;\nuse crate::credentials::SecurityLevel;\nuse crate::credentials::ServerCredentials;\nuse crate::credentials::call::CallCredentials;\nuse crate::credentials::client::ClientConnectionSecurityContext;\nuse crate::credentials::client::ClientConnectionSecurityInfo;\nuse crate::credentials::client::ClientHandshakeInfo;\nuse crate::credentials::client::HandshakeOutput;\nuse crate::credentials::client::{self};\nuse crate::credentials::common::Authority;\nuse crate::credentials::server::ServerConnectionSecurityInfo;\nuse crate::credentials::server::{self};\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\n\n/// An implementation of [`ChannelCredentials`] for insecure connections.\n///\n/// This credential type does not perform any encryption or authentication. It\n/// simply passes the raw underlying transport as the output.\n#[derive(Debug, Clone, Default)]\npub struct InsecureChannelCredentials {\n    _private: (),\n}\n\npub const PROTOCOL_NAME: &str = \"insecure\";\n\nimpl InsecureChannelCredentials {\n    /// Creates a new instance of `InsecureChannelCredentials`.\n    pub fn new() -> Self {\n        Self { _private: () }\n    }\n}\n\n/// An implementation of [`ClientConnectionSecurityContext`] for insecure connections.\n#[derive(Debug, Clone)]\npub struct InsecureConnectionSecurityContext;\n\nimpl ClientConnectionSecurityContext for InsecureConnectionSecurityContext {\n    fn validate_authority(&self, _authority: &Authority) -> bool {\n        true\n    }\n}\n\nimpl client::ChannelCredsInternal for InsecureChannelCredentials {\n    type ContextType = InsecureConnectionSecurityContext;\n    type Output<I> = I;\n\n    async fn connect<Input: GrpcEndpoint>(\n        &self,\n        _authority: &Authority,\n        source: Input,\n        _info: ClientHandshakeInfo,\n        _runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<Self::Output<Input>, Self::ContextType>, String> {\n        Ok(HandshakeOutput {\n            endpoint: source,\n            security: ClientConnectionSecurityInfo::new(\n                PROTOCOL_NAME,\n                SecurityLevel::NoSecurity,\n                InsecureConnectionSecurityContext,\n                Attributes::new(),\n            ),\n        })\n    }\n\n    fn get_call_credentials(&self) -> Option<&Arc<dyn CallCredentials>> {\n        None\n    }\n}\n\nimpl ChannelCredentials for InsecureChannelCredentials {\n    fn info(&self) -> &ProtocolInfo {\n        static INFO: ProtocolInfo = ProtocolInfo::new(PROTOCOL_NAME);\n        &INFO\n    }\n}\n\n/// An implementation of [`ServerCredentials`] for insecure connections.\n#[derive(Debug, Clone, Default)]\npub struct InsecureServerCredentials {\n    _private: (),\n}\n\nimpl InsecureServerCredentials {\n    pub fn new() -> Self {\n        Self { _private: () }\n    }\n}\n\nimpl server::ServerCredsInternal for InsecureServerCredentials {\n    type Output<I> = I;\n\n    async fn accept<Input: GrpcEndpoint>(\n        &self,\n        source: Input,\n        _runtime: GrpcRuntime,\n    ) -> Result<server::HandshakeOutput<Self::Output<Input>>, String> {\n        Ok(server::HandshakeOutput {\n            endpoint: source,\n            security: ServerConnectionSecurityInfo::new(\n                PROTOCOL_NAME,\n                SecurityLevel::NoSecurity,\n                Attributes::new(),\n            ),\n        })\n    }\n}\n\nimpl ServerCredentials for InsecureServerCredentials {\n    fn info(&self) -> &ProtocolInfo {\n        static INFO: ProtocolInfo = ProtocolInfo::new(PROTOCOL_NAME);\n        &INFO\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use tokio::io::AsyncReadExt;\n    use tokio::io::AsyncWriteExt;\n    use tokio::net::TcpListener;\n    use tokio::net::TcpStream;\n\n    use super::*;\n    use crate::credentials::ChannelCredentials;\n    use crate::credentials::InsecureChannelCredentials;\n    use crate::credentials::InsecureServerCredentials;\n    use crate::credentials::SecurityLevel;\n    use crate::credentials::ServerCredentials;\n    use crate::credentials::client::ChannelCredsInternal as ClientSealed;\n    use crate::credentials::client::ClientConnectionSecurityContext;\n    use crate::credentials::client::ClientHandshakeInfo;\n    use crate::credentials::common::Authority;\n    use crate::credentials::server::ServerCredsInternal;\n    use crate::rt::GrpcEndpoint;\n    use crate::rt::TcpOptions;\n    use crate::rt::{self};\n\n    #[tokio::test]\n    async fn test_insecure_client_credentials() {\n        let creds = InsecureChannelCredentials::new();\n\n        let info = creds.info();\n        assert_eq!(info.security_protocol(), PROTOCOL_NAME);\n\n        let addr = \"127.0.0.1:0\";\n        let listener = TcpListener::bind(addr).await.unwrap();\n        let server_addr = listener.local_addr().unwrap();\n        let authority = Authority::new(\"localhost\".to_string(), Some(server_addr.port()));\n\n        let runtime = rt::default_runtime();\n        let endpoint = runtime\n            .tcp_stream(server_addr, TcpOptions::default())\n            .await\n            .unwrap();\n        let handshake_info = ClientHandshakeInfo::default();\n\n        let output = creds\n            .connect(&authority, endpoint, handshake_info, runtime)\n            .await\n            .unwrap();\n\n        let mut endpoint = output.endpoint;\n        let security_info = output.security;\n\n        // Verify security info.\n        assert_eq!(security_info.security_protocol(), PROTOCOL_NAME);\n        assert_eq!(security_info.security_level(), SecurityLevel::NoSecurity);\n\n        // Verify data transfer.\n        let (mut server_stream, _) = listener.accept().await.unwrap();\n        assert_eq!(\n            endpoint.get_local_address(),\n            &server_stream.peer_addr().unwrap().to_string()\n        );\n        let test_data = b\"hello grpc\";\n        server_stream.write_all(test_data).await.unwrap();\n\n        let mut buf = vec![0u8; test_data.len()];\n        endpoint.read_exact(&mut buf).await.unwrap();\n        assert_eq!(buf, test_data);\n\n        // Validate arbitrary authority.\n        assert!(\n            security_info\n                .security_context()\n                .validate_authority(&authority)\n        );\n    }\n\n    #[tokio::test]\n    async fn test_insecure_server_credentials() {\n        let creds = InsecureServerCredentials::new();\n\n        let info = creds.info();\n        assert_eq!(info.security_protocol, PROTOCOL_NAME);\n\n        let addr = \"127.0.0.1:0\";\n        let runtime = rt::default_runtime();\n        let mut listener = runtime\n            .listen_tcp(addr.parse().unwrap(), TcpOptions::default())\n            .await\n            .unwrap();\n        let server_addr = *listener.local_addr();\n\n        let client_handle = tokio::spawn(async move {\n            let mut stream = TcpStream::connect(server_addr).await.unwrap();\n            let data = b\"hello grpc\";\n            stream.write_all(data).await.unwrap();\n\n            // Keep the connection alive for a bit so server can read.\n            let mut buf = vec![0u8; 1];\n            let _ = stream.read(&mut buf).await;\n        });\n\n        let (server_stream, _) = listener.accept().await.unwrap();\n\n        let output = creds.accept(server_stream, runtime).await.unwrap();\n        let mut endpoint = output.endpoint;\n        let security_info = output.security;\n\n        assert_eq!(security_info.security_protocol(), PROTOCOL_NAME);\n        assert_eq!(security_info.security_level(), SecurityLevel::NoSecurity);\n\n        let mut buf = vec![0u8; 10];\n        endpoint.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf[..], b\"hello grpc\");\n\n        client_handle.abort();\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/local.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::net::SocketAddr;\nuse std::str::FromStr;\nuse std::sync::Arc;\n\nuse crate::attributes::Attributes;\nuse crate::client::name_resolution::TCP_IP_NETWORK_TYPE;\nuse crate::credentials::ChannelCredentials;\nuse crate::credentials::ProtocolInfo;\nuse crate::credentials::SecurityLevel;\nuse crate::credentials::ServerCredentials;\nuse crate::credentials::call::CallCredentials;\nuse crate::credentials::client;\nuse crate::credentials::client::ClientConnectionSecurityContext;\nuse crate::credentials::client::ClientConnectionSecurityInfo;\nuse crate::credentials::client::ClientHandshakeInfo;\nuse crate::credentials::client::HandshakeOutput;\nuse crate::credentials::common::Authority;\nuse crate::credentials::server;\nuse crate::credentials::server::ServerConnectionSecurityInfo;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\n\npub const PROTOCOL_NAME: &str = \"local\";\n\n/// An implementation of [`ChannelCredentials`] for connections on the same\n/// machine.\n///\n/// This credential type does not perform any encryption or authentication. It\n/// simply passes the raw underlying transport as the output.\n#[derive(Debug, Clone, Default)]\npub struct LocalChannelCredentials {\n    _private: (),\n}\n\nimpl LocalChannelCredentials {\n    /// Creates a new instance of `InsecureChannelCredentials`.\n    pub fn new() -> Self {\n        Self { _private: () }\n    }\n}\n\n/// An implementation of [`ClientConnectionSecurityContext`] for local\n/// connections.\n#[derive(Debug, Clone)]\npub struct LocalConnectionSecurityContext;\n\nimpl ClientConnectionSecurityContext for LocalConnectionSecurityContext {\n    fn validate_authority(&self, _authority: &Authority) -> bool {\n        true\n    }\n}\n\n/// Returns the security level for a local connection.\n/// It returns an error if a connection is not local.\n/// Refer to L62: https://github.com/grpc/proposal/blob/master/L62-core-call-credential-security-level.md\nfn security_level_for_endpoint(\n    peer_addr: &str,\n    network_type: &str,\n) -> Result<SecurityLevel, String> {\n    if network_type == TCP_IP_NETWORK_TYPE\n        && SocketAddr::from_str(peer_addr)\n            .map_err(|e| e.to_string())?\n            .ip()\n            .is_loopback()\n    {\n        return Ok(SecurityLevel::NoSecurity);\n    }\n    // TODO: Add support for unix sockets.\n    Err(format!(\n        \"local credentials rejected connection to non-local address {}\",\n        peer_addr\n    ))\n}\n\nimpl client::ChannelCredsInternal for LocalChannelCredentials {\n    type ContextType = LocalConnectionSecurityContext;\n    type Output<I> = I;\n\n    async fn connect<Input: GrpcEndpoint>(\n        &self,\n        _authority: &Authority,\n        source: Input,\n        _info: ClientHandshakeInfo,\n        _runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<Self::Output<Input>, Self::ContextType>, String> {\n        let security_level =\n            security_level_for_endpoint(source.get_peer_address(), source.get_network_type())?;\n        Ok(HandshakeOutput {\n            endpoint: source,\n            security: ClientConnectionSecurityInfo::new(\n                PROTOCOL_NAME,\n                security_level,\n                LocalConnectionSecurityContext,\n                Attributes::new(),\n            ),\n        })\n    }\n\n    fn get_call_credentials(&self) -> Option<&Arc<dyn CallCredentials>> {\n        None\n    }\n}\n\nimpl ChannelCredentials for LocalChannelCredentials {\n    fn info(&self) -> &ProtocolInfo {\n        static INFO: ProtocolInfo = ProtocolInfo::new(PROTOCOL_NAME);\n        &INFO\n    }\n}\n\n/// An implementation of [`ServerCredentials`] for local connections.\n#[derive(Debug, Clone, Default)]\npub struct LocalServerCredentials {\n    _private: (),\n}\n\nimpl LocalServerCredentials {\n    pub fn new() -> Self {\n        Self { _private: () }\n    }\n}\n\nimpl server::ServerCredsInternal for LocalServerCredentials {\n    type Output<I> = I;\n\n    async fn accept<Input: GrpcEndpoint>(\n        &self,\n        source: Input,\n        _runtime: GrpcRuntime,\n    ) -> Result<server::HandshakeOutput<Self::Output<Input>>, String> {\n        let security_level =\n            security_level_for_endpoint(source.get_peer_address(), source.get_network_type())?;\n        Ok(server::HandshakeOutput {\n            endpoint: source,\n            security: ServerConnectionSecurityInfo::new(\n                PROTOCOL_NAME,\n                security_level,\n                Attributes::new(),\n            ),\n        })\n    }\n}\n\nimpl ServerCredentials for LocalServerCredentials {\n    fn info(&self) -> &ProtocolInfo {\n        static INFO: ProtocolInfo = ProtocolInfo::new(PROTOCOL_NAME);\n        &INFO\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use tokio::io::AsyncReadExt;\n    use tokio::io::AsyncWriteExt;\n    use tokio::net::TcpListener;\n    use tokio::net::TcpStream;\n\n    use super::*;\n    use crate::credentials::ChannelCredentials;\n    use crate::credentials::SecurityLevel;\n    use crate::credentials::ServerCredentials;\n    use crate::credentials::client::ChannelCredsInternal as ClientSealed;\n    use crate::credentials::client::ClientConnectionSecurityContext;\n    use crate::credentials::client::ClientHandshakeInfo;\n    use crate::credentials::common::Authority;\n    use crate::credentials::server::ServerCredsInternal;\n    use crate::rt;\n    use crate::rt::GrpcEndpoint;\n    use crate::rt::TcpOptions;\n\n    #[test]\n    fn test_security_level_for_endpoint_success() {\n        assert_eq!(\n            security_level_for_endpoint(\"127.0.0.1:8080\", TCP_IP_NETWORK_TYPE),\n            Ok(SecurityLevel::NoSecurity)\n        );\n        assert_eq!(\n            security_level_for_endpoint(\"[::1]:8080\", TCP_IP_NETWORK_TYPE),\n            Ok(SecurityLevel::NoSecurity)\n        );\n    }\n\n    #[test]\n    fn test_security_level_for_endpoint_failure() {\n        assert!(security_level_for_endpoint(\"192.168.1.1:8080\", TCP_IP_NETWORK_TYPE).is_err());\n        assert!(security_level_for_endpoint(\"127.0.0.1:8080\", \"unix\").is_err());\n        assert!(security_level_for_endpoint(\"invalid\", TCP_IP_NETWORK_TYPE).is_err());\n    }\n\n    #[tokio::test]\n    async fn test_local_client_credentials() {\n        let creds = LocalChannelCredentials::new();\n\n        let info = creds.info();\n        assert_eq!(info.security_protocol(), \"local\");\n\n        let addr = \"127.0.0.1:0\";\n        let listener = TcpListener::bind(addr).await.unwrap();\n        let server_addr = listener.local_addr().unwrap();\n        let authority = Authority::new(\"localhost\".to_string(), Some(server_addr.port()));\n\n        let runtime = rt::default_runtime();\n        let endpoint = runtime\n            .tcp_stream(server_addr, TcpOptions::default())\n            .await\n            .unwrap();\n        let handshake_info = ClientHandshakeInfo::default();\n\n        let output = creds\n            .connect(&authority, endpoint, handshake_info, runtime)\n            .await\n            .unwrap();\n\n        let mut endpoint = output.endpoint;\n        let security_info = output.security;\n\n        // Verify security info.\n        assert_eq!(security_info.security_protocol(), \"local\");\n        assert_eq!(security_info.security_level(), SecurityLevel::NoSecurity);\n\n        // Verify data transfer.\n        let (mut server_stream, _) = listener.accept().await.unwrap();\n        assert_eq!(\n            endpoint.get_local_address(),\n            &server_stream.peer_addr().unwrap().to_string()\n        );\n        let test_data = b\"hello grpc\";\n        server_stream.write_all(test_data).await.unwrap();\n\n        let mut buf = vec![0u8; test_data.len()];\n        endpoint.read_exact(&mut buf).await.unwrap();\n        assert_eq!(buf, test_data);\n\n        // Validate arbitrary authority.\n        assert!(\n            security_info\n                .security_context()\n                .validate_authority(&authority)\n        );\n    }\n\n    #[tokio::test]\n    async fn test_local_server_credentials() {\n        let creds = LocalServerCredentials::new();\n\n        let info = creds.info();\n        assert_eq!(info.security_protocol, \"local\");\n\n        let addr = \"127.0.0.1:0\";\n        let runtime = rt::default_runtime();\n        let mut listener = runtime\n            .listen_tcp(addr.parse().unwrap(), TcpOptions::default())\n            .await\n            .unwrap();\n        let server_addr = *listener.local_addr();\n\n        let client_handle = tokio::spawn(async move {\n            let mut stream = TcpStream::connect(server_addr).await.unwrap();\n            let data = b\"hello grpc\";\n            stream.write_all(data).await.unwrap();\n\n            // Keep the connection alive for a bit so server can read.\n            let mut buf = vec![0u8; 1];\n            let _ = stream.read(&mut buf).await;\n        });\n\n        let (server_stream, _) = listener.accept().await.unwrap();\n\n        let output = creds.accept(server_stream, runtime).await.unwrap();\n        let mut endpoint = output.endpoint;\n        let security_info = output.security;\n\n        assert_eq!(security_info.security_protocol(), \"local\");\n        assert_eq!(security_info.security_level(), SecurityLevel::NoSecurity);\n\n        let mut buf = vec![0u8; 10];\n        endpoint.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf[..], b\"hello grpc\");\n\n        client_handle.abort();\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/mod.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\npub mod call;\npub(crate) mod client;\npub(crate) mod dyn_wrapper;\nmod insecure;\nmod local;\n#[cfg(feature = \"tls-rustls\")]\npub mod rustls;\npub(crate) mod server;\n\npub use client::CompositeChannelCredentials;\npub use insecure::InsecureChannelCredentials;\npub use insecure::InsecureServerCredentials;\npub use local::LocalChannelCredentials;\npub use local::LocalServerCredentials;\n\n/// Defines the common interface for all live gRPC wire protocols and supported\n/// transport security protocols (e.g., TLS, ALTS).\npub trait ChannelCredentials: client::ChannelCredsInternal + Sync + 'static {\n    //// Provides the ProtocolInfo of these credentials.\n    fn info(&self) -> &ProtocolInfo;\n}\n\npub trait ServerCredentials: server::ServerCredsInternal + Sync + 'static {\n    //// Provides the ProtocolInfo of this credentials.\n    fn info(&self) -> &ProtocolInfo;\n}\n\n/// Defines the level of protection provided by an established connection.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]\n#[non_exhaustive]\npub enum SecurityLevel {\n    /// The connection is insecure; no protection is applied.\n    NoSecurity,\n    /// The connection guarantees data integrity (tamper-proofing) but not\n    /// privacy.\n    ///\n    /// Payloads are visible to observers but cannot be modified without\n    /// detection.\n    IntegrityOnly,\n    /// The connection guarantees both privacy (confidentiality) and data\n    /// integrity.\n    ///\n    /// This is the standard level for secure transports like TLS.\n    PrivacyAndIntegrity,\n}\n\npub(crate) mod common {\n    /// Represents the value passed as the `:authority` pseudo-header, typically\n    /// in the form `host:port`.\n    pub struct Authority {\n        host: String,\n        port: Option<u16>,\n    }\n\n    impl Authority {\n        pub fn new(host: String, port: Option<u16>) -> Self {\n            Self { host, port }\n        }\n\n        pub fn host(&self) -> &str {\n            &self.host\n        }\n\n        pub fn port(&self) -> Option<u16> {\n            self.port\n        }\n    }\n}\n\npub struct ProtocolInfo {\n    security_protocol: &'static str,\n}\n\nimpl ProtocolInfo {\n    pub(crate) const fn new(security_protocol: &'static str) -> Self {\n        Self { security_protocol }\n    }\n\n    pub fn security_protocol(&self) -> &'static str {\n        self.security_protocol\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/rustls/client/mod.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\nuse rustls::crypto::CryptoProvider;\nuse rustls_pki_types::CertificateDer;\nuse rustls_pki_types::ServerName;\nuse rustls_platform_verifier::BuilderVerifierExt;\nuse tokio::sync::watch::Receiver;\nuse tokio_rustls::TlsConnector;\nuse tokio_rustls::TlsStream as RustlsStream;\n\nuse crate::attributes::Attributes;\nuse crate::credentials::ChannelCredentials;\nuse crate::credentials::ProtocolInfo;\nuse crate::credentials::SecurityLevel;\nuse crate::credentials::call::CallCredentials;\nuse crate::credentials::client;\nuse crate::credentials::client::ClientConnectionSecurityContext;\nuse crate::credentials::client::ClientConnectionSecurityInfo;\nuse crate::credentials::client::ClientHandshakeInfo;\nuse crate::credentials::client::HandshakeOutput;\nuse crate::credentials::common::Authority;\nuse crate::credentials::rustls::ALPN_PROTO_STR_H2;\nuse crate::credentials::rustls::Identity;\nuse crate::credentials::rustls::Provider;\nuse crate::credentials::rustls::RootCertificates;\nuse crate::credentials::rustls::TLS_PROTO_INFO;\nuse crate::credentials::rustls::key_log::KeyLogFile;\nuse crate::credentials::rustls::parse_certs;\nuse crate::credentials::rustls::parse_key;\nuse crate::credentials::rustls::sanitize_crypto_provider;\nuse crate::credentials::rustls::tls_stream::TlsStream;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\n\n#[cfg(test)]\nmod test;\n\n/// Configuration for client-side TLS settings.\npub struct ClientTlsConfig {\n    pem_roots_provider: Option<Receiver<RootCertificates>>,\n    identity_provider: Option<Receiver<Identity>>,\n    key_log_path: Option<PathBuf>,\n}\n\nimpl ClientTlsConfig {\n    pub fn new() -> Self {\n        ClientTlsConfig {\n            pem_roots_provider: None,\n            identity_provider: None,\n            key_log_path: None,\n        }\n    }\n\n    /// Configures the set of PEM-encoded root certificates (CA) to trust.\n    ///\n    /// These certificates are used to validate the server's certificate chain.\n    /// If this is not called, the client generally defaults to using the\n    /// system's native certificate store.\n    pub fn with_root_certificates_provider<R>(mut self, provider: R) -> Self\n    where\n        R: Provider<RootCertificates>,\n    {\n        self.pem_roots_provider = Some(provider.get_receiver());\n        self\n    }\n\n    /// Configures the client's identity for Mutual TLS (mTLS).\n    ///\n    /// This provides the client's certificate chain and private key.\n    /// If this is not called, the client will not present a certificate\n    /// to the server (standard one-way TLS).\n    pub fn with_identity_provider<I>(mut self, provider: I) -> Self\n    where\n        I: Provider<Identity>,\n    {\n        self.identity_provider = Some(provider.get_receiver());\n        self\n    }\n\n    /// Sets the path where TLS session keys will be logged.\n    ///\n    /// # Security\n    ///\n    /// This should be used **only for debugging purposes**. It should never be\n    /// used in a production environment due to security concerns.\n    pub fn insecure_with_key_log_path(mut self, path: impl Into<PathBuf>) -> Self {\n        self.key_log_path = Some(path.into());\n        self\n    }\n}\n\nimpl Default for ClientTlsConfig {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[derive(Clone)]\npub struct RustlsClientTlsCredendials {\n    connector: TlsConnector,\n}\n\nimpl RustlsClientTlsCredendials {\n    /// Constructs a new `ClientTlsCredendials` instance from the provided\n    /// configuration.\n    pub fn new(config: ClientTlsConfig) -> Result<RustlsClientTlsCredendials, String> {\n        let provider = if let Some(p) = CryptoProvider::get_default() {\n            p.as_ref().clone()\n        } else {\n            return Err(\n                \"No crypto provider installed. Enable `tls-aws-lc` feature in rustls or install one manually.\"\n                .to_string()\n            );\n        };\n\n        Self::new_impl(config, provider)\n    }\n\n    fn new_impl(\n        mut config: ClientTlsConfig,\n        provider: CryptoProvider,\n    ) -> Result<RustlsClientTlsCredendials, String> {\n        let provider = sanitize_crypto_provider(provider)?;\n        let builder = rustls::ClientConfig::builder_with_provider(Arc::new(provider))\n            .with_protocol_versions(&[&rustls::version::TLS13, &rustls::version::TLS12])\n            .map_err(|e| e.to_string())?;\n\n        let builder = if let Some(mut roots_provider) = config.pem_roots_provider.take() {\n            let mut root_store = rustls::RootCertStore::empty();\n            let ca_pem = roots_provider.borrow_and_update();\n            let certs = parse_certs(ca_pem.get_ref())?;\n            for cert in certs {\n                root_store.add(cert).map_err(|e| e.to_string())?;\n            }\n            builder.with_root_certificates(root_store)\n        } else {\n            // Use system root certificates.\n            builder\n                .with_platform_verifier()\n                .map_err(|e| e.to_string())?\n        };\n\n        let mut client_config = if let Some(mut identity_provider) = config.identity_provider.take()\n        {\n            let identity = identity_provider.borrow_and_update();\n            let certs = parse_certs(&identity.certs)?;\n            let key = parse_key(&identity.key)?;\n            builder\n                .with_client_auth_cert(certs, key)\n                .map_err(|e| e.to_string())?\n        } else {\n            builder.with_no_client_auth()\n        };\n\n        client_config.alpn_protocols = vec![ALPN_PROTO_STR_H2.to_vec()];\n        client_config.resumption = rustls::client::Resumption::disabled();\n        if let Some(path) = config.key_log_path {\n            client_config.key_log = Arc::new(KeyLogFile::new(&path))\n        }\n\n        Ok(RustlsClientTlsCredendials {\n            connector: TlsConnector::from(Arc::new(client_config)),\n        })\n    }\n}\n\npub struct ClientTlsSecContext {\n    verified_peer_cert: Option<CertificateDer<'static>>,\n}\n\nimpl ClientConnectionSecurityContext for ClientTlsSecContext {\n    fn validate_authority(&self, authority: &Authority) -> bool {\n        let server_name = match ServerName::try_from(authority.host()) {\n            Ok(n) => n,\n            Err(_) => return false,\n        };\n\n        let cert_der = match &self.verified_peer_cert {\n            Some(c) => c,\n            None => return false,\n        };\n\n        let cert = match webpki::EndEntityCert::try_from(cert_der) {\n            Ok(c) => c,\n            Err(_) => return false,\n        };\n\n        cert.verify_is_valid_for_subject_name(&server_name).is_ok()\n    }\n}\n\nimpl client::ChannelCredsInternal for RustlsClientTlsCredendials {\n    type ContextType = ClientTlsSecContext;\n    type Output<I> = TlsStream<I>;\n    async fn connect<Input: GrpcEndpoint>(\n        &self,\n        authority: &Authority,\n        source: Input,\n        _info: ClientHandshakeInfo,\n        _rt: GrpcRuntime,\n    ) -> Result<HandshakeOutput<TlsStream<Input>, ClientTlsSecContext>, String> {\n        let server_name = ServerName::try_from(authority.host())\n            .map_err(|e| format!(\"invalid authority: {}\", e))?\n            .to_owned();\n\n        let tls_stream = self\n            .connector\n            .connect(server_name, source)\n            .await\n            .map_err(|e| e.to_string())?;\n\n        let (_io, connection) = tls_stream.get_ref();\n        if let Some(negotiated) = connection.alpn_protocol() {\n            if negotiated != ALPN_PROTO_STR_H2 {\n                return Err(\"Server negotiated unexpected ALPN protocol\".into());\n            }\n        } else {\n            // Strict Enforcement: Fail if server didn't select ALPN\n            return Err(\"Server did not negotiate ALPN (h2 required)\".into());\n        }\n        let peer_cert = connection\n            .peer_certificates()\n            .and_then(|certs| certs.first())\n            .map(|c| c.clone().into_owned());\n\n        let cs_info = ClientConnectionSecurityInfo::new(\n            \"tls\",\n            SecurityLevel::PrivacyAndIntegrity,\n            ClientTlsSecContext {\n                verified_peer_cert: peer_cert,\n            },\n            Attributes::new(),\n        );\n        let ep = TlsStream::new(RustlsStream::Client(tls_stream));\n        Ok(HandshakeOutput {\n            endpoint: ep,\n            security: cs_info,\n        })\n    }\n\n    fn get_call_credentials(&self) -> Option<&Arc<dyn CallCredentials>> {\n        None\n    }\n}\n\nimpl ChannelCredentials for RustlsClientTlsCredendials {\n    fn info(&self) -> &ProtocolInfo {\n        &TLS_PROTO_INFO\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/rustls/client/test.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::net::SocketAddr;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse std::sync::Once;\n\nuse rustls::HandshakeKind;\nuse rustls::ServerConfig;\nuse rustls::crypto::ring;\nuse rustls_pki_types::CertificateDer;\nuse rustls_pki_types::PrivateKeyDer;\nuse tempfile::NamedTempFile;\nuse tokio::io::AsyncReadExt;\nuse tokio::io::AsyncWriteExt;\nuse tokio::net::TcpListener;\nuse tokio::task::JoinHandle;\nuse tokio_rustls::TlsAcceptor;\n\nuse crate::credentials::client::ChannelCredsInternal;\nuse crate::credentials::client::ClientConnectionSecurityContext;\nuse crate::credentials::client::ClientHandshakeInfo;\nuse crate::credentials::common::Authority;\nuse crate::credentials::rustls::ALPN_PROTO_STR_H2;\nuse crate::credentials::rustls::Identity;\nuse crate::credentials::rustls::RootCertificates;\nuse crate::credentials::rustls::StaticProvider;\nuse crate::credentials::rustls::client::ClientTlsConfig;\nuse crate::credentials::rustls::client::RustlsClientTlsCredendials;\nuse crate::rt;\nuse crate::rt::TcpOptions;\n\nstatic INIT: Once = Once::new();\n\nfn init_provider() {\n    INIT.call_once(|| {\n        let _ = ring::default_provider().install_default();\n    });\n}\n\n#[tokio::test]\nasync fn test_tls_handshake() {\n    init_provider();\n    run_handshake_test(vec![ALPN_PROTO_STR_H2.to_vec()], true).await;\n}\n\n#[tokio::test]\nasync fn test_tls_handshake_no_alpn() {\n    init_provider();\n    // Server provides NO ALPN. Client requires \"h2\".\n    run_handshake_test(vec![], false).await;\n}\n\n#[tokio::test]\nasync fn test_tls_handshake_bad_alpn() {\n    init_provider();\n    // Server provides HTTP/1.1 ALPN. Client requires \"h2\".\n    run_handshake_test(vec![b\"http/1.1\".to_vec()], false).await;\n}\n\n#[tokio::test]\nasync fn test_tls_handshake_alpn_h1_and_h2() {\n    init_provider();\n    // Server provides HTTP/1.1 and H2 ALPN. Client requires \"h2\".\n    run_handshake_test(vec![b\"http/1.1\".to_vec(), b\"h2\".to_vec()], true).await;\n}\n\n#[tokio::test]\nasync fn test_tls_cipher_suites_secure() {\n    init_provider();\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n    let config = ClientTlsConfig::new().with_root_certificates_provider(root_provider);\n\n    let provider = rustls::crypto::CryptoProvider::get_default()\n        .expect(\"No default crypto provider found\")\n        .as_ref()\n        .clone();\n\n    // This should succeed as default provider usually has secure suites.\n    let creds = RustlsClientTlsCredendials::new_impl(config, provider);\n    assert!(\n        creds.is_ok(),\n        \"Failed to create creds with secure provider: {:?}\",\n        creds.err()\n    );\n}\n\n#[tokio::test]\nasync fn test_tls_cipher_suites_insecure() {\n    init_provider();\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n    let config = ClientTlsConfig::new().with_root_certificates_provider(root_provider);\n\n    let mut provider = rustls::crypto::CryptoProvider::get_default()\n        .expect(\"No default crypto provider found\")\n        .as_ref()\n        .clone();\n\n    fn is_secure(suported_suite: &rustls::SupportedCipherSuite) -> bool {\n        match suported_suite {\n            rustls::SupportedCipherSuite::Tls13(_) => true,\n            rustls::SupportedCipherSuite::Tls12(suite) => matches!(\n                suite.common.suite,\n                rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256\n            ),\n        }\n    }\n\n    // Remove all cipher suites that are considered secure by our policy\n    provider.cipher_suites.retain(|suite| !is_secure(suite));\n\n    let creds = RustlsClientTlsCredendials::new_impl(config, provider);\n    assert!(creds.err().unwrap().contains(\"no cipher suites matching\"));\n}\n\n#[tokio::test]\nasync fn test_tls_key_log() {\n    init_provider();\n\n    let key_log_file = NamedTempFile::new().expect(\"failed to create a temporary file.\");\n\n    // Server setup\n    let server_config = default_server_config();\n    let (addr, server_task) = setup_server(server_config).await;\n\n    // Client setup\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n    let config = ClientTlsConfig::new()\n        .with_root_certificates_provider(root_provider)\n        .insecure_with_key_log_path(key_log_file.path());\n\n    let creds = RustlsClientTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let endpoint = runtime\n        .tcp_stream(addr, TcpOptions::default())\n        .await\n        .unwrap();\n    let authority = Authority::new(\"localhost\".to_string(), Some(addr.port()));\n\n    let result = creds\n        .connect(\n            &authority,\n            endpoint,\n            ClientHandshakeInfo::default(),\n            runtime,\n        )\n        .await\n        .expect(\"Handshake failed\");\n    let mut stream = result.endpoint;\n    let mut buf = Vec::new();\n    let _ = stream.read_to_end(&mut buf).await;\n    assert_eq!(buf, b\"Hello world\");\n\n    server_task.await.unwrap();\n\n    // Verify key log file has content.\n    let content = std::fs::read_to_string(key_log_file.path()).unwrap();\n    assert!(!content.is_empty(), \"Key log file is empty\");\n    // CLIENT_HANDSHAKE_TRAFFIC_SECRET is standard for TLS 1.3\n    assert!(\n        content.contains(\"CLIENT_HANDSHAKE_TRAFFIC_SECRET\"),\n        \"Key log missing expected content: {}\",\n        content\n    );\n}\n\n#[tokio::test]\nasync fn test_tls_handshake_wrong_server_name() {\n    init_provider();\n\n    // Server setup\n    let server_config = default_server_config();\n    let (addr, server_task) = setup_server(server_config).await;\n\n    // Client setup\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n    let config = ClientTlsConfig::new().with_root_certificates_provider(root_provider);\n\n    let creds = RustlsClientTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let endpoint = runtime\n        .tcp_stream(addr, TcpOptions::default())\n        .await\n        .unwrap();\n\n    let authority = Authority::new(\n        // Use a hostname not in the server cert's SANs\n        \"wrong.host.com\".to_string(),\n        Some(addr.port()),\n    );\n\n    let result = creds\n        .connect(\n            &authority,\n            endpoint,\n            ClientHandshakeInfo::default(),\n            runtime,\n        )\n        .await;\n\n    assert!(\n        result.is_err(),\n        \"Handshake should fail with wrong server name\"\n    );\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_validate_authority() {\n    init_provider();\n\n    // Server setup\n    let server_config = default_server_config();\n\n    let acceptor = TlsAcceptor::from(Arc::new(server_config));\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n\n    let server_task = tokio::spawn(async move {\n        if let Ok((stream, _)) = listener.accept().await {\n            // Complete handshake and hold connection\n            if let Ok(mut stream) = acceptor.accept(stream).await {\n                // Keep connection open for client to verify\n                let _ = stream.read_u8().await;\n            }\n        }\n    });\n\n    // Client setup.\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n    let config = ClientTlsConfig::new().with_root_certificates_provider(root_provider);\n\n    let creds = RustlsClientTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let endpoint = runtime\n        .tcp_stream(addr, TcpOptions::default())\n        .await\n        .unwrap();\n\n    let authority = Authority::new(\"localhost\".to_string(), Some(addr.port()));\n\n    let result = creds\n        .connect(\n            &authority,\n            endpoint,\n            ClientHandshakeInfo::default(),\n            runtime,\n        )\n        .await\n        .expect(\"Handshake failed\");\n\n    let context = result.security.security_context();\n\n    // Validate correct authorities\n    assert!(context.validate_authority(&Authority::new(\"localhost\".to_string(), None)));\n    assert!(context.validate_authority(&Authority::new(\"example.com\".to_string(), None)));\n    assert!(context.validate_authority(&Authority::new(\"127.0.0.1\".to_string(), None)));\n\n    // Validate incorrect authorities\n    assert!(!context.validate_authority(&Authority::new(\"wrong.host\".to_string(), None)));\n    assert!(!context.validate_authority(&Authority::new(\"grpc.io\".to_string(), None)));\n}\n\n#[tokio::test]\nasync fn test_mtls_handshake_no_identity() {\n    init_provider();\n\n    // Server setup (Requires Client Auth)\n    let server_config = mtls_server_config();\n    let (addr, server_task) = setup_server(server_config).await;\n\n    let config = ClientTlsConfig::new()\n        .with_root_certificates_provider(StaticProvider::new(load_root_certs(\"ca.pem\")));\n\n    let creds = RustlsClientTlsCredendials::new(config).unwrap();\n    let runtime = rt::default_runtime();\n    let endpoint = runtime\n        .tcp_stream(addr, TcpOptions::default())\n        .await\n        .unwrap();\n    let authority = Authority::new(\"localhost\".to_string(), Some(addr.port()));\n\n    // In TLS 1.3, the client considers the handshake complete immediately after\n    // sending its Certificate and Finished messages. It does not wait for the\n    // server to validate them.\n    // Consequently, connect() returns success, but the server will subsequently\n    // process the credentials, reject them, and close the connection with an\n    // Alert. Therefore, the connection succeeds, but the first read on the\n    // stream must fail.\n    let result = creds\n        .connect(\n            &authority,\n            endpoint,\n            ClientHandshakeInfo::default(),\n            runtime,\n        )\n        .await\n        .expect(\"Client handshake expected to succeed with TLS 1.3\");\n\n    let mut stream = result.endpoint;\n    let mut buf = Vec::new();\n    let res = stream.read_to_end(&mut buf).await;\n    assert!(\n        res.is_err(),\n        \"read from TLS stream should fail due to missing client identity\"\n    );\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_mtls_handshake_with_identitiy() {\n    init_provider();\n\n    // Server setup (Requires Client Auth)\n    let server_config = mtls_server_config();\n    let (addr, server_task) = setup_server(server_config).await;\n\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n\n    let identity = load_identity(\"client1.pem\", \"client1.key\");\n    let identity_provider = StaticProvider::new(identity);\n\n    let config = ClientTlsConfig::new()\n        .with_root_certificates_provider(root_provider)\n        .with_identity_provider(identity_provider);\n\n    let creds = RustlsClientTlsCredendials::new(config).unwrap();\n    let runtime = rt::default_runtime();\n    let endpoint = runtime\n        .tcp_stream(addr, TcpOptions::default())\n        .await\n        .unwrap();\n    let authority = Authority::new(\"localhost\".to_string(), Some(addr.port()));\n\n    let result = creds\n        .connect(\n            &authority,\n            endpoint,\n            ClientHandshakeInfo::default(),\n            runtime,\n        )\n        .await\n        .expect(\"Handshake failed with client identity\");\n\n    let mut stream = result.endpoint;\n    let mut buf = Vec::new();\n    let _ = stream.read_to_end(&mut buf).await;\n    assert_eq!(buf, b\"Hello world\");\n\n    server_task.await.unwrap();\n}\n\nasync fn check_client_resumption_disabled(\n    versions: Vec<&'static rustls::SupportedProtocolVersion>,\n) {\n    init_provider();\n\n    // Server setup: Support resumption\n    let certs = load_certs(\"server.pem\");\n    let key = load_private_key(\"server.key\");\n    let provider = ring::default_provider();\n    let mut server_config = ServerConfig::builder_with_provider(Arc::new(provider))\n        .with_protocol_versions(&versions)\n        .expect(\"invalid versions\")\n        .with_no_client_auth()\n        .with_single_cert(certs, key)\n        .unwrap();\n    server_config.alpn_protocols = vec![ALPN_PROTO_STR_H2.to_vec()];\n    // Enable stateful resumption\n    server_config.session_storage = rustls::server::ServerSessionMemoryCache::new(32);\n    // Enable stateless resumption (TLS 1.3 tickets)\n    server_config.send_tls13_tickets = 1;\n\n    let (addr, server_task) = setup_server_multi_connection(server_config, 2).await;\n\n    // Client setup\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n    let config = ClientTlsConfig::new().with_root_certificates_provider(root_provider);\n\n    let creds = RustlsClientTlsCredendials::new(config).unwrap();\n\n    for i in 0..2 {\n        let runtime = rt::default_runtime();\n        let endpoint = runtime\n            .tcp_stream(addr, TcpOptions::default())\n            .await\n            .unwrap();\n        let authority = Authority::new(\"localhost\".to_string(), Some(addr.port()));\n\n        let result = creds\n            .connect(\n                &authority,\n                endpoint,\n                ClientHandshakeInfo::default(),\n                runtime,\n            )\n            .await\n            .expect(\"Handshake failed\");\n\n        let mut tls_stream = result.endpoint;\n\n        let connection = match tls_stream.inner() {\n            tokio_rustls::TlsStream::Client(conn) => conn.get_ref().1,\n            _ => panic!(\"Expected client stream\"),\n        };\n\n        assert_eq!(\n            connection.handshake_kind(),\n            Some(HandshakeKind::Full),\n            \"Expected full handshake on attempt {}\",\n            i\n        );\n\n        let mut buf = Vec::new();\n        let _ = tls_stream.read_to_end(&mut buf).await;\n        assert_eq!(buf, b\"Hello world\");\n    }\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_resumption_disabled_tls13() {\n    check_client_resumption_disabled(vec![&rustls::version::TLS13]).await;\n}\n\n#[tokio::test]\nasync fn test_tls_resumption_disabled_tls12() {\n    check_client_resumption_disabled(vec![&rustls::version::TLS12]).await;\n}\n\nfn load_identity(cert_file: &str, key_file: &str) -> Identity {\n    let cert = std::fs::read(test_certs_path().join(cert_file)).expect(\"cannot read cert file\");\n    let key = std::fs::read(test_certs_path().join(key_file)).expect(\"cannot read key file\");\n    Identity::from_pem(cert, key)\n}\n\nfn mtls_server_config() -> ServerConfig {\n    let certs = load_certs(\"server.pem\");\n    let key = load_private_key(\"server.key\");\n\n    let client_ca_path = test_certs_path().join(\"client_ca.pem\");\n    let file = std::fs::File::open(client_ca_path).expect(\"cannot open client CA file\");\n    let mut reader = std::io::BufReader::new(file);\n    let mut root_store = rustls::RootCertStore::empty();\n    for cert in rustls_pemfile::certs(&mut reader) {\n        root_store.add(cert.unwrap()).unwrap();\n    }\n\n    let verifier = rustls::server::WebPkiClientVerifier::builder(Arc::new(root_store))\n        .build()\n        .unwrap();\n\n    let mut server_config = ServerConfig::builder()\n        .with_client_cert_verifier(verifier)\n        .with_single_cert(certs, key)\n        .unwrap();\n    server_config.alpn_protocols = vec![ALPN_PROTO_STR_H2.to_vec()];\n    server_config\n}\n\nfn test_certs_path() -> PathBuf {\n    PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"))\n        .parent()\n        .unwrap()\n        .join(\"examples/data/tls\")\n}\n\nfn load_certs(filename: &str) -> Vec<CertificateDer<'static>> {\n    let path = test_certs_path().join(filename);\n    let file = std::fs::File::open(path).expect(\"cannot open certificate file\");\n    let mut reader = std::io::BufReader::new(file);\n    rustls_pemfile::certs(&mut reader)\n        .map(|result| result.unwrap())\n        .collect()\n}\n\nfn load_private_key(filename: &str) -> PrivateKeyDer<'static> {\n    let path = test_certs_path().join(filename);\n    let file = std::fs::File::open(path).expect(\"cannot open private key file\");\n    let mut reader = std::io::BufReader::new(file);\n    loop {\n        match rustls_pemfile::read_one(&mut reader).expect(\"cannot read private key\") {\n            Some(rustls_pemfile::Item::Pkcs1Key(key)) => return key.into(),\n            Some(rustls_pemfile::Item::Pkcs8Key(key)) => return key.into(),\n            Some(rustls_pemfile::Item::Sec1Key(key)) => return key.into(),\n            None => panic!(\"no keys found\"),\n            _ => {}\n        }\n    }\n}\n\nfn load_root_certs(filename: &str) -> RootCertificates {\n    let path = test_certs_path().join(filename);\n    let ca_pem = std::fs::read(path).unwrap();\n    RootCertificates::from_pem(ca_pem)\n}\n\nfn default_server_config() -> ServerConfig {\n    let certs = load_certs(\"server.pem\");\n    let key = load_private_key(\"server.key\");\n    let mut server_config = ServerConfig::builder()\n        .with_no_client_auth()\n        .with_single_cert(certs, key)\n        .unwrap();\n    server_config.alpn_protocols = vec![ALPN_PROTO_STR_H2.to_vec()];\n    server_config\n}\n\nasync fn setup_server(config: ServerConfig) -> (SocketAddr, JoinHandle<()>) {\n    setup_server_multi_connection(config, 1).await\n}\n\nasync fn setup_server_multi_connection(\n    config: ServerConfig,\n    count: usize,\n) -> (SocketAddr, JoinHandle<()>) {\n    let acceptor = TlsAcceptor::from(Arc::new(config));\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n\n    let task = tokio::spawn(async move {\n        for _ in 0..count {\n            let (stream, _) = listener.accept().await.unwrap();\n            let acceptor = acceptor.clone();\n            tokio::spawn(async move {\n                match acceptor.accept(stream).await {\n                    Ok(mut stream) => {\n                        let _ = stream.write_all(b\"Hello world\").await;\n                        let _ = stream.shutdown().await;\n                    }\n                    Err(err) => {\n                        println!(\"TLS handshake failed: {}\", err)\n                    }\n                }\n            });\n        }\n    });\n    (addr, task)\n}\n\nasync fn run_handshake_test(server_alpn: Vec<Vec<u8>>, expect_success: bool) {\n    // Server setup\n    let mut server_config = default_server_config();\n    server_config.alpn_protocols = server_alpn;\n    let (addr, server_task) = setup_server(server_config).await;\n\n    // Client setup\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n\n    let config = ClientTlsConfig::new().with_root_certificates_provider(root_provider);\n\n    let creds = RustlsClientTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let endpoint = runtime\n        .tcp_stream(addr, TcpOptions::default())\n        .await\n        .unwrap();\n\n    let authority = Authority::new(\"localhost\".to_string(), Some(addr.port()));\n\n    let result = creds\n        .connect(\n            &authority,\n            endpoint,\n            ClientHandshakeInfo::default(),\n            runtime,\n        )\n        .await;\n\n    if expect_success {\n        assert!(result.is_ok(), \"Handshake failed: {:?}\", result.err());\n        let result = result.unwrap();\n        let mut stream = result.endpoint;\n        let mut buf = Vec::new();\n        // Ignore read errors if server closed connection abruptly (which happens in failure cases, but here we expect success)\n        let _ = stream.read_to_end(&mut buf).await;\n        assert_eq!(buf, b\"Hello world\");\n    } else {\n        assert!(result.is_err(), \"Handshake succeeded but expected failure\");\n    }\n\n    server_task.await.unwrap();\n}\n"
  },
  {
    "path": "grpc/src/credentials/rustls/key_log.rs",
    "content": "// Copyright (c) 2016 Joseph Birr-Pixton <jpixton@gmail.com>\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// \thttp://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// Note: This file contains modifications by the gRPC authors; see revision history for details.\n\nuse core::fmt::Debug;\nuse core::fmt::Formatter;\nuse std::fs::File;\nuse std::fs::OpenOptions;\nuse std::io;\nuse std::io::Write;\nuse std::path::PathBuf;\nuse std::sync::Mutex;\n\nuse rustls::KeyLog;\n\n// Internal mutable state for KeyLogFile\nstruct KeyLogFileInner {\n    file: Option<File>,\n    buf: Vec<u8>,\n}\n\nimpl KeyLogFileInner {\n    fn new(path: &PathBuf) -> Self {\n        let file = match OpenOptions::new().append(true).create(true).open(path) {\n            Ok(f) => Some(f),\n            Err(e) => {\n                eprintln!(\"unable to create key log file {path:?}: {e}\");\n                None\n            }\n        };\n\n        Self {\n            file,\n            buf: Vec::new(),\n        }\n    }\n\n    fn try_write(&mut self, label: &str, client_random: &[u8], secret: &[u8]) -> io::Result<()> {\n        let Some(file) = &mut self.file else {\n            return Ok(());\n        };\n\n        self.buf.truncate(0);\n        write!(self.buf, \"{label} \")?;\n        for b in client_random.iter() {\n            write!(self.buf, \"{b:02x}\")?;\n        }\n        write!(self.buf, \" \")?;\n        for b in secret.iter() {\n            write!(self.buf, \"{b:02x}\")?;\n        }\n        writeln!(self.buf)?;\n        file.write_all(&self.buf)\n    }\n}\n\nimpl Debug for KeyLogFileInner {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        f.debug_struct(\"KeyLogFileInner\")\n            // Note: we omit self.buf deliberately as it may contain key data.\n            .field(\"file\", &self.file)\n            .finish_non_exhaustive()\n    }\n}\n\n/// [`KeyLog`] implementation that opens a file whose name is\n/// given to the constructor, and writes keys into it.\n///\n/// If such a file cannot be opened, or cannot be written then\n/// this does nothing but logs errors.\npub struct KeyLogFile(Mutex<KeyLogFileInner>);\n\nimpl KeyLogFile {\n    /// Makes a new `KeyLogFile`.  The environment variable is\n    /// inspected and the named file is opened during this call.\n    pub fn new(path: &PathBuf) -> Self {\n        Self(Mutex::new(KeyLogFileInner::new(path)))\n    }\n}\n\nimpl KeyLog for KeyLogFile {\n    fn log(&self, label: &str, client_random: &[u8], secret: &[u8]) {\n        match self\n            .0\n            .lock()\n            .unwrap()\n            .try_write(label, client_random, secret)\n        {\n            Ok(()) => {}\n            Err(e) => {\n                eprintln!(\"error writing to key log file: {e}\");\n            }\n        }\n    }\n}\n\nimpl Debug for KeyLogFile {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        match self.0.try_lock() {\n            Ok(key_log_file) => write!(f, \"{key_log_file:?}\"),\n            Err(_) => write!(f, \"KeyLogFile {{ <locked> }}\"),\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/rustls/mod.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::io::BufReader;\n\nuse rustls::crypto::CryptoProvider;\nuse rustls::pki_types::PrivateKeyDer;\nuse rustls_pki_types::CertificateDer;\nuse tokio::sync::watch;\n\nuse crate::credentials::ProtocolInfo;\n\npub mod client;\nmod key_log;\npub mod server;\nmod tls_stream;\n\nconst ALPN_PROTO_STR_H2: &[u8; 2] = b\"h2\";\n\n/// Represents a X509 certificate chain.\n#[derive(Debug, Clone)]\npub struct RootCertificates {\n    pem: Vec<u8>,\n}\n\nimpl RootCertificates {\n    /// Parse a PEM encoded X509 Certificate.\n    ///\n    /// The provided PEM should include at least one PEM encoded certificate.\n    pub fn from_pem(pem: impl AsRef<[u8]>) -> Self {\n        let pem = pem.as_ref().into();\n        Self { pem }\n    }\n\n    /// Get a immutable reference to underlying certificate\n    fn get_ref(&self) -> &[u8] {\n        self.pem.as_slice()\n    }\n}\n\n/// Represents a private key and X509 certificate chain.\n#[derive(Debug, Clone)]\npub struct Identity {\n    certs: Vec<u8>,\n    key: Vec<u8>,\n}\n\npub type IdentityList = Vec<Identity>;\n\nimpl Identity {\n    /// Parse a PEM encoded certificate and private key.\n    ///\n    /// The provided cert must contain at least one PEM encoded certificate.\n    pub fn from_pem(cert: impl AsRef<[u8]>, key: impl AsRef<[u8]>) -> Self {\n        let cert = cert.as_ref().into();\n        let key = key.as_ref().into();\n        Self { certs: cert, key }\n    }\n}\n\nmod provider {\n    use tokio::sync::watch::Receiver;\n\n    /// A sealed trait to prevent downstream implementations of `Provider`.\n    ///\n    /// This trait exposes the internal mechanism (Tokio watch channel) used to\n    /// receive updates. It is kept private/restricted to ensure that `Provider`\n    /// can only be implemented by types defined within this crate.\n    pub trait ProviderInternal<T> {\n        /// Returns a clone of the underlying watch receiver.\n        ///\n        /// This allows the consumer to observe the current value and await\n        /// future updates.\n        fn get_receiver(self) -> Receiver<T>;\n    }\n}\n\n/// A source of configuration or state of type `T` that allows for dynamic\n/// updates.\n///\n/// This trait abstracts over the source of the data (e.g., static memory,\n/// file system, network) and provides a uniform interface for consumers to\n/// access the current value and subscribe to changes.\n///\n/// # Sealed Trait\n///\n/// This trait is **sealed**. It cannot be implemented by downstream crates.\n/// Users should rely on the provided implementations (e.g.,\n/// `StaticIdentityProvider`, `StaticRootsProvider`).\npub trait Provider<T>: provider::ProviderInternal<T> {}\n\n/// A provider that supplies a constant, immutable value.\npub struct StaticProvider<T> {\n    inner: T,\n}\n\nimpl<T> StaticProvider<T> {\n    /// Creates a new `StaticProvider` with the given fixed value.\n    pub fn new(value: T) -> Self {\n        Self { inner: value }\n    }\n}\n\nimpl<T> provider::ProviderInternal<T> for StaticProvider<T> {\n    fn get_receiver(self) -> watch::Receiver<T> {\n        // We drop the sender (_) immediately.\n        // This ensures the receiver sees the initial value but knows\n        // no future updates will arrive.\n        let (_tx, rx) = watch::channel(self.inner);\n        rx\n    }\n}\n\nimpl<T> Provider<T> for StaticProvider<T> {}\n\npub type StaticRootCertificatesProvider = StaticProvider<RootCertificates>;\npub type StaticIdentityProvider = StaticProvider<Identity>;\n\nstatic TLS_PROTO_INFO: ProtocolInfo = ProtocolInfo {\n    security_protocol: \"tls\",\n};\n\nfn sanitize_crypto_provider(mut crypto_provider: CryptoProvider) -> Result<CryptoProvider, String> {\n    crypto_provider.cipher_suites.retain(|suite| match suite {\n        rustls::SupportedCipherSuite::Tls13(suite) => true,\n        rustls::SupportedCipherSuite::Tls12(suite) => {\n            matches!(\n                suite.common.suite,\n                rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256\n            )\n        }\n    });\n\n    if crypto_provider.cipher_suites.is_empty() {\n        return Err(\"Crypto provider has no cipher suites matching the security policy (TLS1.3 or TLS1.2+ECDHE)\".to_string());\n    }\n\n    Ok(crypto_provider)\n}\n\nfn parse_certs(pem: &[u8]) -> Result<Vec<CertificateDer<'static>>, String> {\n    let mut reader = BufReader::new(pem);\n    rustls_pemfile::certs(&mut reader)\n        .map(|result| result.map_err(|e| e.to_string()))\n        .collect()\n}\n\nfn parse_key(pem: &[u8]) -> Result<PrivateKeyDer<'static>, String> {\n    let mut reader = BufReader::new(pem);\n    loop {\n        match rustls_pemfile::read_one(&mut reader).map_err(|e| e.to_string())? {\n            Some(rustls_pemfile::Item::Pkcs1Key(key)) => return Ok(key.into()),\n            Some(rustls_pemfile::Item::Pkcs8Key(key)) => return Ok(key.into()),\n            Some(rustls_pemfile::Item::Sec1Key(key)) => return Ok(key.into()),\n            None => return Err(\"no private key found\".to_string()),\n            _ => continue,\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/rustls/server/mod.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\nuse rustls::crypto::CryptoProvider;\nuse rustls::server::ClientHello;\nuse rustls::server::ProducesTickets;\nuse rustls::server::ResolvesServerCert;\nuse rustls::sign::CertifiedKey;\nuse tokio::sync::watch::Receiver;\nuse tokio_rustls::TlsAcceptor;\nuse tokio_rustls::TlsStream as RustlsStream;\nuse webpki::EndEntityCert;\n\nuse crate::attributes::Attributes;\nuse crate::credentials::ProtocolInfo;\nuse crate::credentials::SecurityLevel;\nuse crate::credentials::ServerCredentials;\nuse crate::credentials::rustls::ALPN_PROTO_STR_H2;\nuse crate::credentials::rustls::IdentityList;\nuse crate::credentials::rustls::Provider;\nuse crate::credentials::rustls::RootCertificates;\nuse crate::credentials::rustls::StaticRootCertificatesProvider;\nuse crate::credentials::rustls::TLS_PROTO_INFO;\nuse crate::credentials::rustls::key_log::KeyLogFile;\nuse crate::credentials::rustls::parse_certs;\nuse crate::credentials::rustls::parse_key;\nuse crate::credentials::rustls::provider::ProviderInternal;\nuse crate::credentials::rustls::sanitize_crypto_provider;\nuse crate::credentials::rustls::tls_stream::TlsStream;\nuse crate::credentials::server::HandshakeOutput;\nuse crate::credentials::server::ServerConnectionSecurityInfo;\nuse crate::credentials::server::ServerCredsInternal;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\n\n#[cfg(test)]\nmod test;\n\n#[derive(Debug)]\nstruct SniResolver {\n    keys: Vec<Arc<CertifiedKey>>,\n}\n\nimpl ResolvesServerCert for SniResolver {\n    fn resolve(&self, client_hello: ClientHello) -> Option<Arc<CertifiedKey>> {\n        if self.keys.len() == 1 {\n            return Some(self.keys[0].clone());\n        }\n\n        if let Some(subject_name) = client_hello\n            .server_name()\n            .and_then(|sni| rustls_pki_types::ServerName::try_from(sni).ok())\n        {\n            for key in &self.keys {\n                let Some(cert) = key.cert.first() else {\n                    continue;\n                };\n                let Ok(end_entity_cert) = EndEntityCert::try_from(cert) else {\n                    continue;\n                };\n\n                if end_entity_cert\n                    .verify_is_valid_for_subject_name(&subject_name)\n                    .is_ok()\n                {\n                    return Some(key.clone());\n                }\n            }\n        }\n        self.keys.first().cloned()\n    }\n}\n\n#[non_exhaustive]\npub enum TlsClientCertificateRequestType<R = StaticRootCertificatesProvider> {\n    /// Server does not request client certificate.\n    ///\n    /// This is the default behavior.\n    ///\n    /// The certificate presented by the client is not checked by the server at\n    /// all. (A client may present a self-signed or signed certificate or not\n    /// present a certificate at all and any of those option would be accepted).\n    DontRequest,\n\n    /// Server requests client certificate but does not enforce that the client\n    /// presents a certificate.\n    ///\n    /// If the client presents a certificate, the client authentication is done by\n    /// the gRPC framework. For a successful connection the client needs to either\n    /// present a certificate that can be verified against the `pem_root_certs`\n    /// or not present a certificate at all.\n    ///\n    /// The client's key certificate pair must be valid for the TLS connection to\n    /// be established.\n    RequestAndVerify { roots_provider: R },\n\n    /// Server requests client certificate and enforces that the client presents a\n    /// certificate.\n    ///\n    /// The certificate presented by the client is verified by the gRPC framework.\n    /// For a successful connection the client needs to present a certificate that\n    /// can be verified against the `pem_root_certs`.\n    ///\n    /// The client's key certificate pair must be valid for the TLS connection to\n    /// be established.\n    RequireAndVerify { roots_provider: R },\n}\n\nenum InnerClientCertificateRequestType {\n    DontRequestClientCertificate,\n    RequestClientCertificateAndVerify {\n        roots_provider: Receiver<RootCertificates>,\n    },\n    RequestAndRequireClientCertificateAndVerify {\n        roots_provider: Receiver<RootCertificates>,\n    },\n}\n\nimpl From<TlsClientCertificateRequestType> for InnerClientCertificateRequestType {\n    fn from(value: TlsClientCertificateRequestType) -> Self {\n        match value {\n            TlsClientCertificateRequestType::DontRequest => {\n                InnerClientCertificateRequestType::DontRequestClientCertificate\n            }\n            TlsClientCertificateRequestType::RequestAndVerify { roots_provider } => {\n                InnerClientCertificateRequestType::RequestClientCertificateAndVerify {\n                    roots_provider: roots_provider.get_receiver(),\n                }\n            }\n            TlsClientCertificateRequestType::RequireAndVerify { roots_provider } => {\n                InnerClientCertificateRequestType::RequestAndRequireClientCertificateAndVerify {\n                    roots_provider: roots_provider.get_receiver(),\n                }\n            }\n        }\n    }\n}\n\n#[derive(Clone)]\npub struct RustlsServerTlsCredendials {\n    acceptor: TlsAcceptor,\n}\n\n/// Configuration for server-side TLS settings.\npub struct ServerTlsConfig {\n    identities_provider: Receiver<IdentityList>,\n    request_type: InnerClientCertificateRequestType,\n    key_log_path: Option<PathBuf>,\n}\n\nimpl ServerTlsConfig {\n    pub fn new<I>(identities_provider: I) -> Self\n    where\n        I: Provider<IdentityList>,\n    {\n        ServerTlsConfig {\n            identities_provider: identities_provider.get_receiver(),\n            request_type: TlsClientCertificateRequestType::DontRequest.into(),\n            key_log_path: None,\n        }\n    }\n\n    /// Configures the client certificate request policy for the server.\n    ///\n    /// This determines whether the server requests a client certificate and how\n    /// it verifies it.\n    pub fn with_request_type(mut self, request_type: TlsClientCertificateRequestType) -> Self {\n        self.request_type = request_type.into();\n        self\n    }\n\n    /// Sets the path where TLS session keys will be logged.\n    ///\n    /// # Security\n    ///\n    /// This should be used **only for debugging purposes**. It should never be\n    /// used in a production environment due to security concerns.\n    pub fn insecure_with_key_log_path(mut self, path: impl Into<PathBuf>) -> Self {\n        self.key_log_path = Some(path.into());\n        self\n    }\n}\n\nimpl RustlsServerTlsCredendials {\n    pub fn new(config: ServerTlsConfig) -> Result<RustlsServerTlsCredendials, String> {\n        let provider = if let Some(p) = CryptoProvider::get_default() {\n            p.as_ref().clone()\n        } else {\n            return Err(\n                \"No crypto provider installed. Enable `tls-aws-lc` feature in rustls or install one manually.\"\n                .to_string()\n            );\n        };\n\n        Self::new_impl(config, provider)\n    }\n\n    fn new_impl(\n        mut config: ServerTlsConfig,\n        provider: CryptoProvider,\n    ) -> Result<RustlsServerTlsCredendials, String> {\n        let provider = sanitize_crypto_provider(provider)?;\n        let id_list = config.identities_provider.borrow_and_update().clone();\n        if id_list.is_empty() {\n            return Err(\"need at least one server identity.\".to_string());\n        }\n\n        let verifier = match config.request_type {\n            InnerClientCertificateRequestType::DontRequestClientCertificate => {\n                rustls::server::WebPkiClientVerifier::no_client_auth()\n            }\n            InnerClientCertificateRequestType::RequestClientCertificateAndVerify {\n                mut roots_provider,\n            } => {\n                let roots = roots_provider.borrow_and_update();\n                let certs = parse_certs(&roots.pem)?;\n                let mut root_store = rustls::RootCertStore::empty();\n                for cert in certs {\n                    root_store.add(cert).map_err(|e| e.to_string())?;\n                }\n                rustls::server::WebPkiClientVerifier::builder(Arc::new(root_store))\n                    .allow_unauthenticated()\n                    .build()\n                    .map_err(|e| e.to_string())?\n            }\n            InnerClientCertificateRequestType::RequestAndRequireClientCertificateAndVerify {\n                mut roots_provider,\n            } => {\n                let roots = roots_provider.borrow_and_update();\n                let certs = parse_certs(&roots.pem)?;\n                let mut root_store = rustls::RootCertStore::empty();\n                for cert in certs {\n                    root_store.add(cert).map_err(|e| e.to_string())?;\n                }\n                rustls::server::WebPkiClientVerifier::builder(Arc::new(root_store))\n                    .build()\n                    .map_err(|e| e.to_string())?\n            }\n        };\n\n        let builder = rustls::ServerConfig::builder_with_provider(Arc::new(provider.clone()))\n            .with_protocol_versions(&[&rustls::version::TLS13, &rustls::version::TLS12])\n            .map_err(|e| e.to_string())?\n            .with_client_cert_verifier(verifier);\n\n        let mut keys = Vec::with_capacity(id_list.len());\n        for identity in id_list {\n            let certs = parse_certs(&identity.certs)?;\n            let key = parse_key(&identity.key)?;\n            let signing_key = provider\n                .key_provider\n                .load_private_key(key)\n                .map_err(|e| e.to_string())?;\n\n            keys.push(Arc::new(CertifiedKey::new(certs, signing_key)));\n        }\n\n        let resolver = Arc::new(SniResolver { keys });\n        let mut server_config = builder.with_cert_resolver(resolver);\n\n        server_config.alpn_protocols = vec![ALPN_PROTO_STR_H2.to_vec()];\n        if let Some(path) = config.key_log_path {\n            server_config.key_log = Arc::new(KeyLogFile::new(&path));\n        }\n        // Disable Stateful Resumption (Session IDs).\n        server_config.session_storage = Arc::new(rustls::server::NoServerSessionStorage {});\n\n        // Disable Stateless Resumption (TLS 1.3 Tickets).\n        server_config.send_tls13_tickets = 0;\n        // Disable Stateless Resumption (TLS 1.2 Tickets)\n        // Install a dummy ticketer that refuses to issue tickets.\n        server_config.ticketer = Arc::new(NoTicketer);\n\n        Ok(RustlsServerTlsCredendials {\n            acceptor: TlsAcceptor::from(Arc::new(server_config)),\n        })\n    }\n}\n\n// Helper Struct to Disable Tickets.\n#[derive(Debug)]\nstruct NoTicketer;\n\nimpl ProducesTickets for NoTicketer {\n    fn enabled(&self) -> bool {\n        false\n    }\n    fn lifetime(&self) -> u32 {\n        0\n    }\n    fn encrypt(&self, _plain: &[u8]) -> Option<Vec<u8>> {\n        None\n    }\n    fn decrypt(&self, _cipher: &[u8]) -> Option<Vec<u8>> {\n        None\n    }\n}\n\nimpl ServerCredsInternal for RustlsServerTlsCredendials {\n    type Output<Input> = TlsStream<Input>;\n\n    async fn accept<Input: GrpcEndpoint>(\n        &self,\n        source: Input,\n        _runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<Self::Output<Input>>, String> {\n        let tls_stream = self\n            .acceptor\n            .accept(source)\n            .await\n            .map_err(|e| e.to_string())?;\n\n        let (_io, conn) = tls_stream.get_ref();\n        if conn.alpn_protocol() != Some(ALPN_PROTO_STR_H2) {\n            return Err(\"Client ignored ALPN requirements\".into());\n        }\n\n        let auth_info = ServerConnectionSecurityInfo::new(\n            \"tls\",\n            SecurityLevel::PrivacyAndIntegrity,\n            Attributes::new(),\n        );\n        let endpoint = TlsStream::new(RustlsStream::Server(tls_stream));\n        Ok(HandshakeOutput {\n            endpoint,\n            security: auth_info,\n        })\n    }\n}\n\nimpl ServerCredentials for RustlsServerTlsCredendials {\n    fn info(&self) -> &ProtocolInfo {\n        &TLS_PROTO_INFO\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/rustls/server/test.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse std::sync::Once;\n\nuse rustls::HandshakeKind;\nuse rustls::crypto::ring;\nuse rustls_pki_types::ServerName;\nuse tempfile::NamedTempFile;\nuse tokio::io::AsyncReadExt;\nuse tokio::io::AsyncWriteExt;\nuse tokio::net::TcpStream;\nuse tokio_rustls::TlsConnector;\n\nuse crate::credentials::rustls::ALPN_PROTO_STR_H2;\nuse crate::credentials::rustls::Identity;\nuse crate::credentials::rustls::RootCertificates;\nuse crate::credentials::rustls::StaticProvider;\nuse crate::credentials::rustls::server::RustlsServerTlsCredendials;\nuse crate::credentials::rustls::server::ServerTlsConfig;\nuse crate::credentials::rustls::server::TlsClientCertificateRequestType;\nuse crate::credentials::server::ServerCredsInternal;\nuse crate::rt::TcpOptions;\nuse crate::rt::{self};\n\nstatic INIT: Once = Once::new();\n\nfn init_provider() {\n    INIT.call_once(|| {\n        let _ = ring::default_provider().install_default();\n    });\n}\n\n#[tokio::test]\nasync fn test_tls_server_handshake() {\n    init_provider();\n    let client_alpn = vec![ALPN_PROTO_STR_H2.to_vec()];\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n    let config = ServerTlsConfig::new(identity_provider);\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let result = creds.accept(stream, runtime).await;\n        assert!(\n            result.is_ok(),\n            \"Server handshake failed: {:?}\",\n            result.err()\n        );\n        let mut stream = result.unwrap().endpoint;\n        let mut buf = [0u8; 5];\n        stream.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf, b\"ping!\");\n        stream.write_all(b\"pong!\").await.unwrap();\n    });\n\n    // Client setup\n    let mut client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    client_config.alpn_protocols = client_alpn;\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    let result = connector.connect(domain, stream).await;\n\n    assert!(\n        result.is_ok(),\n        \"Client handshake failed: {:?}\",\n        result.err()\n    );\n\n    let mut tls_stream = result.unwrap();\n    tls_stream.write_all(b\"ping!\").await.unwrap();\n    let mut buf = [0u8; 5];\n    tls_stream.read_exact(&mut buf).await.unwrap();\n    assert_eq!(&buf, b\"pong!\");\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_handshake_no_alpn() {\n    init_provider();\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n    let config = ServerTlsConfig::new(identity_provider);\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let result = creds.accept(stream, runtime).await;\n        assert!(result.is_err(), \"Server handshake should have failed\");\n    });\n\n    // Client setup\n    let mut client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    client_config.alpn_protocols = vec![];\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    let result = connector.connect(domain, stream).await;\n\n    // Handshake will fail after the handshake is complete no ALPN is skipped.\n    let mut tls_stream = result.unwrap();\n    let _ = tls_stream.write_all(b\"ping!\").await;\n    let mut buf = [0u8; 5];\n    let res = tls_stream.read_exact(&mut buf).await;\n    assert!(res.is_err());\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_handshake_bad_alpn() {\n    init_provider();\n    let client_alpn = vec![b\"http/1.1\".to_vec()];\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n    let config = ServerTlsConfig::new(identity_provider);\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let runtime = rt::default_runtime();\n        let result = creds.accept(stream, runtime).await;\n        assert!(result.is_err(), \"Server handshake should have failed\");\n    });\n\n    // Client setup\n    let mut client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    client_config.alpn_protocols = client_alpn;\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    // Handshake should fail due to incompatible application protocols.\n    let result = connector.connect(domain, stream).await;\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_handshake_alpn_h1_and_h2() {\n    init_provider();\n    let client_alpn = vec![b\"http/1.1\".to_vec(), ALPN_PROTO_STR_H2.to_vec()];\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n    let config = ServerTlsConfig::new(identity_provider);\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let runtime = rt::default_runtime();\n        let result = creds.accept(stream, runtime).await.unwrap();\n    });\n\n    // Client setup\n    let mut client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    client_config.alpn_protocols = client_alpn;\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    // Handshake should succeed.\n    let result = connector.connect(domain, stream).await.unwrap();\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_mtls_require_fail() {\n    init_provider();\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n\n    let root_certs = load_root_certs(\"ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n\n    let config = ServerTlsConfig::new(identity_provider).with_request_type(\n        TlsClientCertificateRequestType::RequireAndVerify {\n            roots_provider: root_provider,\n        },\n    );\n\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let result = creds.accept(stream, runtime).await;\n        assert!(result.is_err(), \"Handshake should fail without client cert\");\n    });\n\n    // Client setup: No identity\n    let mut client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    client_config.alpn_protocols = vec![b\"h2\".to_vec()];\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    let result = connector.connect(domain, stream).await;\n\n    // In TLS 1.3 client assumes the handshake succeeded but first read/write\n    // fails.\n    let mut tls_stream = result.unwrap();\n    let mut buf = [0u8; 1];\n    let res = tls_stream.read(&mut buf).await;\n    assert!(res.is_err());\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_mtls_success() {\n    init_provider();\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n\n    let root_certs = load_root_certs(\"client_ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n\n    let config = ServerTlsConfig::new(identity_provider).with_request_type(\n        TlsClientCertificateRequestType::RequireAndVerify {\n            roots_provider: root_provider,\n        },\n    );\n\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let result = creds\n            .accept(stream, runtime)\n            .await\n            .expect(\"Server handshake failed\");\n        let mut stream = result.endpoint;\n        let mut buf = [0u8; 5];\n        stream.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf, b\"ping!\");\n        stream.write_all(b\"pong!\").await.unwrap();\n    });\n\n    // Client setup: With identity\n    let client_identity_cert = load_certs(\"client1.pem\");\n    let client_identity_key = load_private_key(\"client1.key\");\n\n    let client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_client_auth_cert(client_identity_cert, client_identity_key)\n        .unwrap();\n    let mut client_config = client_config;\n    client_config.alpn_protocols = vec![b\"h2\".to_vec()];\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    let mut tls_stream = connector.connect(domain, stream).await.unwrap();\n    tls_stream.write_all(b\"ping!\").await.unwrap();\n    let mut buf = [0u8; 5];\n    tls_stream.read_exact(&mut buf).await.unwrap();\n    assert_eq!(&buf, b\"pong!\");\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_mtls_optional() {\n    init_provider();\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n\n    let root_certs = load_root_certs(\"client_ca.pem\");\n    let root_provider = StaticProvider::new(root_certs);\n\n    let config = ServerTlsConfig::new(identity_provider).with_request_type(\n        TlsClientCertificateRequestType::RequestAndVerify {\n            roots_provider: root_provider,\n        },\n    );\n\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let result = creds\n            .accept(stream, runtime)\n            .await\n            .expect(\"Server handshake failed\");\n        let mut stream = result.endpoint;\n        let mut buf = [0u8; 5];\n        stream.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf, b\"ping!\");\n        stream.write_all(b\"pong!\").await.unwrap();\n    });\n\n    // Client setup: Without identity\n    let client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    let mut client_config = client_config;\n    client_config.alpn_protocols = vec![b\"h2\".to_vec()];\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    let mut tls_stream = connector.connect(domain, stream).await.unwrap();\n    tls_stream.write_all(b\"ping!\").await.unwrap();\n    let mut buf = [0u8; 5];\n    tls_stream.read_exact(&mut buf).await.unwrap();\n    assert_eq!(&buf, b\"pong!\");\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_key_log() {\n    init_provider();\n    let key_log_file = NamedTempFile::new().expect(\"failed to create a temporary file.\");\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n    let config =\n        ServerTlsConfig::new(identity_provider).insecure_with_key_log_path(key_log_file.path());\n\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        let (stream, _) = listener.accept().await.unwrap();\n        let result = creds\n            .accept(stream, runtime)\n            .await\n            .expect(\"Server handshake failed\");\n        let mut stream = result.endpoint;\n        let mut buf = [0u8; 5];\n        stream.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf, b\"ping!\");\n        stream.write_all(b\"pong!\").await.unwrap();\n    });\n\n    // Client setup\n    let mut client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    client_config.alpn_protocols = vec![b\"h2\".to_vec()];\n\n    let connector = TlsConnector::from(Arc::new(client_config));\n    let stream = TcpStream::connect(addr).await.unwrap();\n    let domain = ServerName::try_from(\"localhost\").unwrap();\n\n    let mut tls_stream = connector.connect(domain, stream).await.unwrap();\n    tls_stream.write_all(b\"ping!\").await.unwrap();\n    let mut buf = [0u8; 5];\n    tls_stream.read_exact(&mut buf).await.unwrap();\n\n    server_task.await.unwrap();\n\n    // Verify key log file exists and has content\n    let content = std::fs::read_to_string(key_log_file.path()).unwrap();\n    assert!(!content.is_empty(), \"Key log file is empty\");\n    assert!(\n        content.contains(\"SERVER_HANDSHAKE_TRAFFIC_SECRET\"),\n        \"Key log missing expected content: {}\",\n        content\n    );\n}\n\nasync fn check_resumption_disabled(versions: Vec<&'static rustls::SupportedProtocolVersion>) {\n    init_provider();\n\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n    let config = ServerTlsConfig::new(identity_provider);\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        for _ in 0..2 {\n            let (stream, _) = listener.accept().await.unwrap();\n            let runtime = rt::default_runtime();\n            let result = creds.accept(stream, runtime).await;\n            assert!(result.is_ok());\n            let mut stream = result.unwrap().endpoint;\n            stream.write_all(b\"pong!\").await.unwrap();\n        }\n    });\n\n    // Client setup with session cache\n    let provider = rustls::crypto::CryptoProvider::get_default()\n        .cloned()\n        .unwrap();\n    let mut client_config = rustls::ClientConfig::builder_with_provider(provider)\n        .with_protocol_versions(&versions)\n        .expect(\"invalid versions\")\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n\n    client_config.resumption = rustls::client::Resumption::in_memory_sessions(32);\n\n    client_config.alpn_protocols = vec![ALPN_PROTO_STR_H2.to_vec()];\n    let connector = TlsConnector::from(Arc::new(client_config));\n\n    for i in 0..2 {\n        let stream = TcpStream::connect(addr).await.unwrap();\n        let domain = ServerName::try_from(\"localhost\").unwrap();\n        let mut tls_stream = connector.connect(domain, stream).await.unwrap();\n\n        let (_, conn) = tls_stream.get_ref();\n        assert_eq!(\n            conn.handshake_kind(),\n            Some(HandshakeKind::Full),\n            \"Expected full handshake on attempt {}\",\n            i\n        );\n\n        let mut buf = [0u8; 5];\n        tls_stream.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf, b\"pong!\");\n    }\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_resumption_disabled_tls13() {\n    check_resumption_disabled(vec![&rustls::version::TLS13]).await;\n}\n\n#[tokio::test]\nasync fn test_tls_server_resumption_disabled_tls12() {\n    check_resumption_disabled(vec![&rustls::version::TLS12]).await;\n}\n\n#[tokio::test]\nasync fn test_tls_server_sni() {\n    init_provider();\n\n    let identity1 = load_identity(\"server.pem\", \"server.key\");\n    let identity2 = load_identity(\"server2.pem\", \"server2.key\");\n    // identity2 has *.test.com\n    let identity_provider = StaticProvider::new(vec![identity1, identity2]);\n    let config = ServerTlsConfig::new(identity_provider);\n    let creds = RustlsServerTlsCredendials::new(config).unwrap();\n\n    let runtime = rt::default_runtime();\n    let mut listener = runtime\n        .listen_tcp(\"127.0.0.1:0\".parse().unwrap(), TcpOptions::default())\n        .await\n        .unwrap();\n    let addr = *listener.local_addr();\n\n    let server_task = tokio::spawn(async move {\n        for _ in 0..2 {\n            let (stream, _) = listener.accept().await.unwrap();\n            let runtime = rt::default_runtime();\n            let result = creds.accept(stream, runtime).await;\n            assert!(\n                result.is_ok(),\n                \"Server handshake failed: {:?}\",\n                result.err()\n            );\n            let mut stream = result.unwrap().endpoint;\n            let mut buf = [0u8; 5];\n            stream.read_exact(&mut buf).await.unwrap();\n            assert_eq!(&buf, b\"ping!\");\n            stream.write_all(b\"pong!\").await.unwrap();\n        }\n    });\n\n    // Client setup\n    let mut client_config = rustls::ClientConfig::builder()\n        .with_root_certificates(create_root_store())\n        .with_no_client_auth();\n    client_config.alpn_protocols = vec![ALPN_PROTO_STR_H2.to_vec()];\n    let connector = TlsConnector::from(Arc::new(client_config));\n\n    let test_com = ServerName::try_from(\"abc.test.com\").unwrap();\n\n    // Request 1: abc.example.com\n    {\n        let stream = TcpStream::connect(addr).await.unwrap();\n        let domain = ServerName::try_from(\"abc.example.com\").unwrap();\n        let mut tls_stream = connector.connect(domain, stream).await.unwrap();\n\n        let (_, conn) = tls_stream.get_ref();\n        let certs = conn.peer_certificates().unwrap();\n        let end_entity = webpki::EndEntityCert::try_from(&certs[0]).unwrap();\n\n        // verify it doesn't have a DNS name of *.test.com\n        assert!(\n            end_entity\n                .verify_is_valid_for_subject_name(&test_com)\n                .is_err()\n        );\n\n        tls_stream.write_all(b\"ping!\").await.unwrap();\n        let mut buf = [0u8; 5];\n        tls_stream.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf, b\"pong!\");\n    }\n\n    // Request 2: abc.test.com\n    {\n        let stream = TcpStream::connect(addr).await.unwrap();\n        let domain = ServerName::try_from(\"abc.test.com\").unwrap();\n        let mut tls_stream = connector.connect(domain, stream).await.unwrap();\n\n        let (_, conn) = tls_stream.get_ref();\n        let certs = conn.peer_certificates().unwrap();\n        let end_entity = webpki::EndEntityCert::try_from(&certs[0]).unwrap();\n\n        // verify that the peer has a certificate with DNS name of *.test.com\n        assert!(\n            end_entity\n                .verify_is_valid_for_subject_name(&test_com)\n                .is_ok()\n        );\n\n        tls_stream.write_all(b\"ping!\").await.unwrap();\n        let mut buf = [0u8; 5];\n        tls_stream.read_exact(&mut buf).await.unwrap();\n        assert_eq!(&buf, b\"pong!\");\n    }\n\n    server_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn test_tls_server_cipher_suites_insecure() {\n    init_provider();\n    let identity = load_identity(\"server.pem\", \"server.key\");\n    let identity_provider = StaticProvider::new(vec![identity]);\n    let config = ServerTlsConfig::new(identity_provider);\n\n    let mut provider = rustls::crypto::CryptoProvider::get_default()\n        .expect(\"No default crypto provider found\")\n        .as_ref()\n        .clone();\n\n    fn is_secure(suported_suite: &rustls::SupportedCipherSuite) -> bool {\n        match suported_suite {\n            rustls::SupportedCipherSuite::Tls13(_) => true,\n            rustls::SupportedCipherSuite::Tls12(suite) => matches!(\n                suite.common.suite,\n                rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\n                    | rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256\n                    | rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256\n            ),\n        }\n    }\n\n    // Remove all cipher suites that are considered secure by gRPC.\n    provider.cipher_suites.retain(|suite| !is_secure(suite));\n\n    let creds = RustlsServerTlsCredendials::new_impl(config, provider);\n    assert!(creds.err().unwrap().contains(\"no cipher suites matching\"));\n}\n\nfn create_root_store() -> rustls::RootCertStore {\n    let root_certs = load_certs(\"ca.pem\");\n    let mut root_store = rustls::RootCertStore::empty();\n    for cert in root_certs {\n        root_store.add(cert).unwrap();\n    }\n    root_store\n}\n\nfn test_certs_path() -> PathBuf {\n    PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"))\n        .parent()\n        .unwrap()\n        .join(\"examples/data/tls\")\n}\n\nfn load_certs(filename: &str) -> Vec<rustls_pki_types::CertificateDer<'static>> {\n    let path = test_certs_path().join(filename);\n    let file = std::fs::File::open(path).expect(\"cannot open certificate file\");\n    let mut reader = std::io::BufReader::new(file);\n    rustls_pemfile::certs(&mut reader)\n        .map(|result| result.unwrap())\n        .collect()\n}\n\nfn load_private_key(filename: &str) -> rustls_pki_types::PrivateKeyDer<'static> {\n    let path = test_certs_path().join(filename);\n    let file = std::fs::File::open(path).expect(\"cannot open private key file\");\n    let mut reader = std::io::BufReader::new(file);\n    loop {\n        match rustls_pemfile::read_one(&mut reader).expect(\"cannot read private key\") {\n            Some(rustls_pemfile::Item::Pkcs1Key(key)) => return key.into(),\n            Some(rustls_pemfile::Item::Pkcs8Key(key)) => return key.into(),\n            Some(rustls_pemfile::Item::Sec1Key(key)) => return key.into(),\n            None => panic!(\"no keys found\"),\n            _ => {}\n        }\n    }\n}\n\nfn load_root_certs(filename: &str) -> RootCertificates {\n    let path = test_certs_path().join(filename);\n    let ca_pem = std::fs::read(path).unwrap();\n    RootCertificates::from_pem(ca_pem)\n}\n\nfn load_identity(cert_file: &str, key_file: &str) -> Identity {\n    let cert = std::fs::read(test_certs_path().join(cert_file)).expect(\"cannot read cert file\");\n    let key = std::fs::read(test_certs_path().join(key_file)).expect(\"cannot read key file\");\n    Identity::from_pem(cert, key)\n}\n"
  },
  {
    "path": "grpc/src/credentials/rustls/tls_stream.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::io::IoSlice;\nuse std::pin::Pin;\nuse std::task::Context;\nuse std::task::Poll;\n\nuse tokio::io::AsyncRead;\nuse tokio::io::AsyncWrite;\nuse tokio::io::ReadBuf;\nuse tokio_rustls::TlsStream as RustlsStream;\n\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::endpoint;\n\npub struct TlsStream<T> {\n    inner: RustlsStream<T>,\n}\n\nimpl<T> AsyncRead for TlsStream<T>\nwhere\n    T: GrpcEndpoint,\n{\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &mut ReadBuf<'_>,\n    ) -> Poll<std::io::Result<()>> {\n        let pinned = Pin::new(&mut self.get_mut().inner);\n        AsyncRead::poll_read(pinned, cx, buf)\n    }\n}\n\nimpl<T> AsyncWrite for TlsStream<T>\nwhere\n    T: GrpcEndpoint,\n{\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        let pinned = Pin::new(&mut self.get_mut().inner);\n        AsyncWrite::poll_write(pinned, cx, buf)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {\n        let pinned = Pin::new(&mut self.get_mut().inner);\n        AsyncWrite::poll_flush(pinned, cx)\n    }\n\n    fn poll_shutdown(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        let pinned = Pin::new(&mut self.get_mut().inner);\n        AsyncWrite::poll_shutdown(pinned, cx)\n    }\n\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[IoSlice<'_>],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        let pinned = Pin::new(&mut self.get_mut().inner);\n        AsyncWrite::poll_write_vectored(pinned, cx, bufs)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        self.inner.is_write_vectored()\n    }\n}\n\nimpl<T> endpoint::Sealed for TlsStream<T> where T: GrpcEndpoint {}\n\nimpl<T> GrpcEndpoint for TlsStream<T>\nwhere\n    T: GrpcEndpoint,\n{\n    fn get_local_address(&self) -> &str {\n        match &self.inner {\n            RustlsStream::Client(s) => s.get_ref().0.get_local_address(),\n            RustlsStream::Server(s) => s.get_ref().0.get_local_address(),\n        }\n    }\n\n    fn get_peer_address(&self) -> &str {\n        match &self.inner {\n            RustlsStream::Client(s) => s.get_ref().0.get_peer_address(),\n            RustlsStream::Server(s) => s.get_ref().0.get_peer_address(),\n        }\n    }\n\n    fn get_network_type(&self) -> &'static str {\n        match &self.inner {\n            RustlsStream::Client(s) => s.get_ref().0.get_network_type(),\n            RustlsStream::Server(s) => s.get_ref().0.get_network_type(),\n        }\n    }\n}\n\nimpl<T> TlsStream<T> {\n    pub fn new(inner: RustlsStream<T>) -> Self {\n        Self { inner }\n    }\n\n    pub fn inner(&self) -> &RustlsStream<T> {\n        &self.inner\n    }\n}\n"
  },
  {
    "path": "grpc/src/credentials/server.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse crate::attributes::Attributes;\nuse crate::credentials::SecurityLevel;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\n\n#[trait_variant::make(Send)]\npub trait ServerCredsInternal {\n    type Output<I>;\n    /// Performs the server-side authentication handshake.\n    ///\n    /// This method wraps the incoming raw `source` connection with the configured\n    /// security protocol (e.g., TLS).\n    ///\n    /// # Returns\n    ///\n    /// A tuple containing:\n    /// 1. The authenticated endpoint (ready for reading/writing frames).\n    async fn accept<Input: GrpcEndpoint>(\n        &self,\n        source: Input,\n        runtime: GrpcRuntime,\n    ) -> Result<HandshakeOutput<Self::Output<Input>>, String>;\n}\n\npub struct HandshakeOutput<T> {\n    pub endpoint: T,\n    pub security: ServerConnectionSecurityInfo,\n}\n\n/// Represents the security state of an established server-side connection.\npub struct ServerConnectionSecurityInfo {\n    security_protocol: &'static str,\n    security_level: SecurityLevel,\n    /// Stores extra data derived from the underlying protocol.\n    attributes: Attributes,\n}\n\nimpl ServerConnectionSecurityInfo {\n    /// Creates a new instance of `ServerConnectionSecurityInfo`.\n    pub fn new(\n        security_protocol: &'static str,\n        security_level: SecurityLevel,\n        attributes: Attributes,\n    ) -> Self {\n        Self {\n            security_protocol,\n            security_level,\n            attributes,\n        }\n    }\n\n    /// Returns the security protocol used.\n    pub fn security_protocol(&self) -> &'static str {\n        self.security_protocol\n    }\n\n    /// Returns the security level of the connection.\n    pub fn security_level(&self) -> SecurityLevel {\n        self.security_level\n    }\n\n    /// Returns the attributes associated with the connection.\n    pub fn attributes(&self) -> &Attributes {\n        &self.attributes\n    }\n}\n"
  },
  {
    "path": "grpc/src/generated/echo_fds.rs",
    "content": "// This file is @generated by codegen.\n// \n// \n//  Copyright 2018 gRPC authors.\n// \n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n// \n//      http://www.apache.org/licenses/LICENSE-2.0\n// \n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n// \n// \n/// Byte encoded FILE_DESCRIPTOR_SET.\npub const FILE_DESCRIPTOR_SET: &[u8] = &[\n    10u8, 246u8, 3u8, 10u8, 15u8, 101u8, 99u8, 104u8, 111u8, 47u8, 101u8, 99u8, 104u8,\n    111u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 18u8, 18u8, 103u8, 114u8, 112u8,\n    99u8, 46u8, 101u8, 120u8, 97u8, 109u8, 112u8, 108u8, 101u8, 115u8, 46u8, 101u8, 99u8,\n    104u8, 111u8, 34u8, 39u8, 10u8, 11u8, 69u8, 99u8, 104u8, 111u8, 82u8, 101u8, 113u8,\n    117u8, 101u8, 115u8, 116u8, 18u8, 24u8, 10u8, 7u8, 109u8, 101u8, 115u8, 115u8, 97u8,\n    103u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 7u8, 109u8, 101u8, 115u8, 115u8,\n    97u8, 103u8, 101u8, 34u8, 40u8, 10u8, 12u8, 69u8, 99u8, 104u8, 111u8, 82u8, 101u8,\n    115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 24u8, 10u8, 7u8, 109u8, 101u8, 115u8,\n    115u8, 97u8, 103u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 7u8, 109u8, 101u8,\n    115u8, 115u8, 97u8, 103u8, 101u8, 50u8, 243u8, 2u8, 10u8, 4u8, 69u8, 99u8, 104u8,\n    111u8, 18u8, 78u8, 10u8, 9u8, 85u8, 110u8, 97u8, 114u8, 121u8, 69u8, 99u8, 104u8,\n    111u8, 18u8, 31u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 101u8, 120u8, 97u8, 109u8,\n    112u8, 108u8, 101u8, 115u8, 46u8, 101u8, 99u8, 104u8, 111u8, 46u8, 69u8, 99u8, 104u8,\n    111u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 26u8, 32u8, 46u8, 103u8,\n    114u8, 112u8, 99u8, 46u8, 101u8, 120u8, 97u8, 109u8, 112u8, 108u8, 101u8, 115u8,\n    46u8, 101u8, 99u8, 104u8, 111u8, 46u8, 69u8, 99u8, 104u8, 111u8, 82u8, 101u8, 115u8,\n    112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 90u8, 10u8, 19u8, 83u8, 101u8, 114u8, 118u8,\n    101u8, 114u8, 83u8, 116u8, 114u8, 101u8, 97u8, 109u8, 105u8, 110u8, 103u8, 69u8,\n    99u8, 104u8, 111u8, 18u8, 31u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 101u8, 120u8,\n    97u8, 109u8, 112u8, 108u8, 101u8, 115u8, 46u8, 101u8, 99u8, 104u8, 111u8, 46u8, 69u8,\n    99u8, 104u8, 111u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 26u8, 32u8, 46u8,\n    103u8, 114u8, 112u8, 99u8, 46u8, 101u8, 120u8, 97u8, 109u8, 112u8, 108u8, 101u8,\n    115u8, 46u8, 101u8, 99u8, 104u8, 111u8, 46u8, 69u8, 99u8, 104u8, 111u8, 82u8, 101u8,\n    115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 48u8, 1u8, 18u8, 90u8, 10u8, 19u8, 67u8,\n    108u8, 105u8, 101u8, 110u8, 116u8, 83u8, 116u8, 114u8, 101u8, 97u8, 109u8, 105u8,\n    110u8, 103u8, 69u8, 99u8, 104u8, 111u8, 18u8, 31u8, 46u8, 103u8, 114u8, 112u8, 99u8,\n    46u8, 101u8, 120u8, 97u8, 109u8, 112u8, 108u8, 101u8, 115u8, 46u8, 101u8, 99u8,\n    104u8, 111u8, 46u8, 69u8, 99u8, 104u8, 111u8, 82u8, 101u8, 113u8, 117u8, 101u8,\n    115u8, 116u8, 26u8, 32u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 101u8, 120u8, 97u8,\n    109u8, 112u8, 108u8, 101u8, 115u8, 46u8, 101u8, 99u8, 104u8, 111u8, 46u8, 69u8, 99u8,\n    104u8, 111u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 40u8, 1u8, 18u8,\n    99u8, 10u8, 26u8, 66u8, 105u8, 100u8, 105u8, 114u8, 101u8, 99u8, 116u8, 105u8, 111u8,\n    110u8, 97u8, 108u8, 83u8, 116u8, 114u8, 101u8, 97u8, 109u8, 105u8, 110u8, 103u8,\n    69u8, 99u8, 104u8, 111u8, 18u8, 31u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 101u8,\n    120u8, 97u8, 109u8, 112u8, 108u8, 101u8, 115u8, 46u8, 101u8, 99u8, 104u8, 111u8,\n    46u8, 69u8, 99u8, 104u8, 111u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 26u8,\n    32u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 101u8, 120u8, 97u8, 109u8, 112u8, 108u8,\n    101u8, 115u8, 46u8, 101u8, 99u8, 104u8, 111u8, 46u8, 69u8, 99u8, 104u8, 111u8, 82u8,\n    101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 40u8, 1u8, 48u8, 1u8, 98u8, 6u8,\n    112u8, 114u8, 111u8, 116u8, 111u8, 51u8,\n];\n"
  },
  {
    "path": "grpc/src/generated/grpc_examples_echo.rs",
    "content": "// This file is @generated by prost-build.\n/// EchoRequest is the request for echo.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct EchoRequest {\n    #[prost(string, tag = \"1\")]\n    pub message: ::prost::alloc::string::String,\n}\n/// EchoResponse is the response for echo.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct EchoResponse {\n    #[prost(string, tag = \"1\")]\n    pub message: ::prost::alloc::string::String,\n}\n/// Generated client implementations.\npub mod echo_client {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    use tonic::codegen::http::Uri;\n    /// Echo is the echo service.\n    #[derive(Debug, Clone)]\n    pub struct EchoClient<T> {\n        inner: tonic::client::Grpc<T>,\n    }\n    impl<T> EchoClient<T>\n    where\n        T: tonic::client::GrpcService<tonic::body::Body>,\n        T::Error: Into<StdError>,\n        T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,\n        <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,\n    {\n        pub fn new(inner: T) -> Self {\n            let inner = tonic::client::Grpc::new(inner);\n            Self { inner }\n        }\n        pub fn with_origin(inner: T, origin: Uri) -> Self {\n            let inner = tonic::client::Grpc::with_origin(inner, origin);\n            Self { inner }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> EchoClient<InterceptedService<T, F>>\n        where\n            F: tonic::service::Interceptor,\n            T::ResponseBody: Default,\n            T: tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n                Response = http::Response<\n                    <T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody,\n                >,\n            >,\n            <T as tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n            >>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,\n        {\n            EchoClient::new(InterceptedService::new(inner, interceptor))\n        }\n        /// Compress requests with the given encoding.\n        ///\n        /// This requires the server to support it otherwise it might respond with an\n        /// error.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.send_compressed(encoding);\n            self\n        }\n        /// Enable decompressing responses.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.accept_compressed(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_decoding_message_size(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_encoding_message_size(limit);\n            self\n        }\n        /// UnaryEcho is unary echo.\n        pub async fn unary_echo(\n            &mut self,\n            request: impl tonic::IntoRequest<super::EchoRequest>,\n        ) -> std::result::Result<tonic::Response<super::EchoResponse>, tonic::Status> {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.examples.echo.Echo/UnaryEcho\",\n            );\n            let mut req = request.into_request();\n            req.extensions_mut()\n                .insert(GrpcMethod::new(\"grpc.examples.echo.Echo\", \"UnaryEcho\"));\n            self.inner.unary(req, path, codec).await\n        }\n        /// ServerStreamingEcho is server side streaming.\n        pub async fn server_streaming_echo(\n            &mut self,\n            request: impl tonic::IntoRequest<super::EchoRequest>,\n        ) -> std::result::Result<\n            tonic::Response<tonic::codec::Streaming<super::EchoResponse>>,\n            tonic::Status,\n        > {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.examples.echo.Echo/ServerStreamingEcho\",\n            );\n            let mut req = request.into_request();\n            req.extensions_mut()\n                .insert(\n                    GrpcMethod::new(\"grpc.examples.echo.Echo\", \"ServerStreamingEcho\"),\n                );\n            self.inner.server_streaming(req, path, codec).await\n        }\n        /// ClientStreamingEcho is client side streaming.\n        pub async fn client_streaming_echo(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<Message = super::EchoRequest>,\n        ) -> std::result::Result<tonic::Response<super::EchoResponse>, tonic::Status> {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.examples.echo.Echo/ClientStreamingEcho\",\n            );\n            let mut req = request.into_streaming_request();\n            req.extensions_mut()\n                .insert(\n                    GrpcMethod::new(\"grpc.examples.echo.Echo\", \"ClientStreamingEcho\"),\n                );\n            self.inner.client_streaming(req, path, codec).await\n        }\n        /// BidirectionalStreamingEcho is bidi streaming.\n        pub async fn bidirectional_streaming_echo(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<Message = super::EchoRequest>,\n        ) -> std::result::Result<\n            tonic::Response<tonic::codec::Streaming<super::EchoResponse>>,\n            tonic::Status,\n        > {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.examples.echo.Echo/BidirectionalStreamingEcho\",\n            );\n            let mut req = request.into_streaming_request();\n            req.extensions_mut()\n                .insert(\n                    GrpcMethod::new(\n                        \"grpc.examples.echo.Echo\",\n                        \"BidirectionalStreamingEcho\",\n                    ),\n                );\n            self.inner.streaming(req, path, codec).await\n        }\n    }\n}\n/// Generated server implementations.\npub mod echo_server {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    /// Generated trait containing gRPC methods that should be implemented for use with EchoServer.\n    #[async_trait]\n    pub trait Echo: std::marker::Send + std::marker::Sync + 'static {\n        /// UnaryEcho is unary echo.\n        async fn unary_echo(\n            &self,\n            request: tonic::Request<super::EchoRequest>,\n        ) -> std::result::Result<tonic::Response<super::EchoResponse>, tonic::Status>;\n        /// Server streaming response type for the ServerStreamingEcho method.\n        type ServerStreamingEchoStream: tonic::codegen::tokio_stream::Stream<\n                Item = std::result::Result<super::EchoResponse, tonic::Status>,\n            >\n            + std::marker::Send\n            + 'static;\n        /// ServerStreamingEcho is server side streaming.\n        async fn server_streaming_echo(\n            &self,\n            request: tonic::Request<super::EchoRequest>,\n        ) -> std::result::Result<\n            tonic::Response<Self::ServerStreamingEchoStream>,\n            tonic::Status,\n        >;\n        /// ClientStreamingEcho is client side streaming.\n        async fn client_streaming_echo(\n            &self,\n            request: tonic::Request<tonic::Streaming<super::EchoRequest>>,\n        ) -> std::result::Result<tonic::Response<super::EchoResponse>, tonic::Status>;\n        /// Server streaming response type for the BidirectionalStreamingEcho method.\n        type BidirectionalStreamingEchoStream: tonic::codegen::tokio_stream::Stream<\n                Item = std::result::Result<super::EchoResponse, tonic::Status>,\n            >\n            + std::marker::Send\n            + 'static;\n        /// BidirectionalStreamingEcho is bidi streaming.\n        async fn bidirectional_streaming_echo(\n            &self,\n            request: tonic::Request<tonic::Streaming<super::EchoRequest>>,\n        ) -> std::result::Result<\n            tonic::Response<Self::BidirectionalStreamingEchoStream>,\n            tonic::Status,\n        >;\n    }\n    /// Echo is the echo service.\n    #[derive(Debug)]\n    pub struct EchoServer<T> {\n        inner: Arc<T>,\n        accept_compression_encodings: EnabledCompressionEncodings,\n        send_compression_encodings: EnabledCompressionEncodings,\n        max_decoding_message_size: Option<usize>,\n        max_encoding_message_size: Option<usize>,\n    }\n    impl<T> EchoServer<T> {\n        pub fn new(inner: T) -> Self {\n            Self::from_arc(Arc::new(inner))\n        }\n        pub fn from_arc(inner: Arc<T>) -> Self {\n            Self {\n                inner,\n                accept_compression_encodings: Default::default(),\n                send_compression_encodings: Default::default(),\n                max_decoding_message_size: None,\n                max_encoding_message_size: None,\n            }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> InterceptedService<Self, F>\n        where\n            F: tonic::service::Interceptor,\n        {\n            InterceptedService::new(Self::new(inner), interceptor)\n        }\n        /// Enable decompressing requests with the given encoding.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.accept_compression_encodings.enable(encoding);\n            self\n        }\n        /// Compress responses with the given encoding, if the client supports it.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.send_compression_encodings.enable(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.max_decoding_message_size = Some(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.max_encoding_message_size = Some(limit);\n            self\n        }\n    }\n    impl<T, B> tonic::codegen::Service<http::Request<B>> for EchoServer<T>\n    where\n        T: Echo,\n        B: Body + std::marker::Send + 'static,\n        B::Error: Into<StdError> + std::marker::Send + 'static,\n    {\n        type Response = http::Response<tonic::body::Body>;\n        type Error = std::convert::Infallible;\n        type Future = BoxFuture<Self::Response, Self::Error>;\n        fn poll_ready(\n            &mut self,\n            _cx: &mut Context<'_>,\n        ) -> Poll<std::result::Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n        fn call(&mut self, req: http::Request<B>) -> Self::Future {\n            match req.uri().path() {\n                \"/grpc.examples.echo.Echo/UnaryEcho\" => {\n                    #[allow(non_camel_case_types)]\n                    struct UnaryEchoSvc<T: Echo>(pub Arc<T>);\n                    impl<T: Echo> tonic::server::UnaryService<super::EchoRequest>\n                    for UnaryEchoSvc<T> {\n                        type Response = super::EchoResponse;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::Response>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<super::EchoRequest>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as Echo>::unary_echo(&inner, request).await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = UnaryEchoSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.unary(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                \"/grpc.examples.echo.Echo/ServerStreamingEcho\" => {\n                    #[allow(non_camel_case_types)]\n                    struct ServerStreamingEchoSvc<T: Echo>(pub Arc<T>);\n                    impl<\n                        T: Echo,\n                    > tonic::server::ServerStreamingService<super::EchoRequest>\n                    for ServerStreamingEchoSvc<T> {\n                        type Response = super::EchoResponse;\n                        type ResponseStream = T::ServerStreamingEchoStream;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::ResponseStream>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<super::EchoRequest>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as Echo>::server_streaming_echo(&inner, request).await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = ServerStreamingEchoSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.server_streaming(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                \"/grpc.examples.echo.Echo/ClientStreamingEcho\" => {\n                    #[allow(non_camel_case_types)]\n                    struct ClientStreamingEchoSvc<T: Echo>(pub Arc<T>);\n                    impl<\n                        T: Echo,\n                    > tonic::server::ClientStreamingService<super::EchoRequest>\n                    for ClientStreamingEchoSvc<T> {\n                        type Response = super::EchoResponse;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::Response>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<tonic::Streaming<super::EchoRequest>>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as Echo>::client_streaming_echo(&inner, request).await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = ClientStreamingEchoSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.client_streaming(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                \"/grpc.examples.echo.Echo/BidirectionalStreamingEcho\" => {\n                    #[allow(non_camel_case_types)]\n                    struct BidirectionalStreamingEchoSvc<T: Echo>(pub Arc<T>);\n                    impl<T: Echo> tonic::server::StreamingService<super::EchoRequest>\n                    for BidirectionalStreamingEchoSvc<T> {\n                        type Response = super::EchoResponse;\n                        type ResponseStream = T::BidirectionalStreamingEchoStream;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::ResponseStream>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<tonic::Streaming<super::EchoRequest>>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as Echo>::bidirectional_streaming_echo(&inner, request)\n                                    .await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = BidirectionalStreamingEchoSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.streaming(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                _ => {\n                    Box::pin(async move {\n                        let mut response = http::Response::new(\n                            tonic::body::Body::default(),\n                        );\n                        let headers = response.headers_mut();\n                        headers\n                            .insert(\n                                tonic::Status::GRPC_STATUS,\n                                (tonic::Code::Unimplemented as i32).into(),\n                            );\n                        headers\n                            .insert(\n                                http::header::CONTENT_TYPE,\n                                tonic::metadata::GRPC_CONTENT_TYPE,\n                            );\n                        Ok(response)\n                    })\n                }\n            }\n        }\n    }\n    impl<T> Clone for EchoServer<T> {\n        fn clone(&self) -> Self {\n            let inner = self.inner.clone();\n            Self {\n                inner,\n                accept_compression_encodings: self.accept_compression_encodings,\n                send_compression_encodings: self.send_compression_encodings,\n                max_decoding_message_size: self.max_decoding_message_size,\n                max_encoding_message_size: self.max_encoding_message_size,\n            }\n        }\n    }\n    /// Generated gRPC service name\n    pub const SERVICE_NAME: &str = \"grpc.examples.echo.Echo\";\n    impl<T> tonic::server::NamedService for EchoServer<T> {\n        const NAME: &'static str = SERVICE_NAME;\n    }\n}\n"
  },
  {
    "path": "grpc/src/inmemory/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::collections::HashMap;\nuse std::sync::Arc;\nuse std::sync::LazyLock;\nuse std::sync::Mutex;\nuse std::sync::atomic::AtomicU64;\nuse std::sync::atomic::Ordering;\n\nuse bytes::Buf;\nuse tokio::sync::Mutex as TokioMutex;\nuse tokio::sync::Notify;\nuse tokio::sync::mpsc;\nuse tokio::sync::oneshot;\n\nuse crate::client::CallOptions;\nuse crate::client::DynRecvStream as ClientDynRecvStream;\nuse crate::client::DynSendStream as ClientDynSendStream;\nuse crate::client::Invoke;\nuse crate::client::RecvStream as ClientRecvStream;\nuse crate::client::SendOptions as ClientSendOptions;\nuse crate::client::SendStream as ClientSendStream;\nuse crate::client::name_resolution::Address;\nuse crate::client::name_resolution::ChannelController as ResolverChannelController;\nuse crate::client::name_resolution::Endpoint;\nuse crate::client::name_resolution::Resolver;\nuse crate::client::name_resolution::ResolverBuilder;\nuse crate::client::name_resolution::ResolverOptions;\nuse crate::client::name_resolution::ResolverUpdate;\nuse crate::client::name_resolution::Target;\nuse crate::client::name_resolution::global_registry as global_resolver_registry;\nuse crate::client::service_config::ServiceConfig;\nuse crate::client::transport::GLOBAL_TRANSPORT_REGISTRY;\nuse crate::client::transport::Transport;\nuse crate::client::transport::TransportOptions;\nuse crate::core::ClientResponseStreamItem;\nuse crate::core::RecvMessage;\nuse crate::core::RequestHeaders;\nuse crate::core::ResponseHeaders;\nuse crate::core::ResponseStreamItem;\nuse crate::core::SendMessage;\nuse crate::core::Trailers;\nuse crate::rt::GrpcRuntime;\nuse crate::server::Call as ServerCall;\nuse crate::server::Listener as ServerListener;\nuse crate::server::RecvStream as ServerRecvStream;\nuse crate::server::SendOptions as ServerSendOptions;\nuse crate::server::SendStream as ServerSendStream;\n\nstatic LISTENERS: LazyLock<Mutex<HashMap<String, mpsc::Sender<InMemoryServerCall>>>> =\n    LazyLock::new(|| Mutex::new(HashMap::new()));\n\nstatic NEXT_ID: AtomicU64 = AtomicU64::new(0);\n\nstruct InMemoryServerCall {\n    headers: RequestHeaders,\n    req_rx: mpsc::UnboundedReceiver<InMemoryRequestStreamItem>,\n    resp_tx: mpsc::UnboundedSender<InMemoryResponseStreamItem>,\n}\n\nenum InMemoryRequestStreamItem {\n    Message(Box<dyn Buf + Send + Sync>),\n    StreamClosed,\n}\n\nenum InMemoryResponseStreamItem {\n    Headers(ResponseHeaders),\n    Message(Box<dyn Buf + Send + Sync>),\n    Trailers(Trailers),\n    StreamClosed,\n}\n\n#[derive(Clone)]\npub struct InMemoryListener {\n    inner: Arc<InMemoryListenerInner>,\n}\n\nstruct InMemoryListenerInner {\n    id: String,\n    r: TokioMutex<mpsc::Receiver<InMemoryServerCall>>,\n    close_notify: Arc<Notify>,\n    drop_notify: Arc<Notify>,\n}\n\nimpl Drop for InMemoryListenerInner {\n    fn drop(&mut self) {\n        self.drop_notify.notify_waiters();\n    }\n}\n\nimpl Default for InMemoryListener {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl InMemoryListener {\n    pub fn new() -> Self {\n        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed).to_string();\n        let (s, r) = mpsc::channel(1);\n        let mut listeners = LISTENERS.lock().unwrap();\n        listeners.insert(id.clone(), s);\n        Self {\n            inner: Arc::new(InMemoryListenerInner {\n                id,\n                r: TokioMutex::new(r),\n                close_notify: Arc::new(Notify::new()),\n                drop_notify: Arc::new(Notify::new()),\n            }),\n        }\n    }\n\n    pub fn id(&self) -> String {\n        self.inner.id.clone()\n    }\n\n    pub async fn close(self) {\n        let id = self.inner.id.clone();\n        let drop_notify = self.inner.drop_notify.clone();\n        let weak = Arc::downgrade(&self.inner);\n\n        LISTENERS.lock().unwrap().remove(&id);\n\n        self.inner.close_notify.notify_waiters();\n\n        drop(self);\n\n        loop {\n            let notified = drop_notify.notified();\n            if weak.upgrade().is_none() {\n                return;\n            }\n            notified.await;\n        }\n    }\n\n    pub async fn await_connection(&self) {}\n}\n\nimpl ServerListener for InMemoryListener {\n    type SendStream = InMemoryServerSendStream;\n    type RecvStream = InMemoryServerRecvStream;\n\n    async fn accept(&self) -> Option<ServerCall<Self::SendStream, Self::RecvStream>> {\n        let mut r = self.inner.r.lock().await;\n        tokio::select! {\n            call = r.recv() => {\n                let call = call?;\n                Some(ServerCall {\n                    headers: call.headers,\n                    send: InMemoryServerSendStream { tx: call.resp_tx },\n                    recv: InMemoryServerRecvStream { rx: call.req_rx },\n                })\n            }\n            _ = self.inner.close_notify.notified() => {\n                None\n            }\n        }\n    }\n}\n\npub struct InMemoryServerSendStream {\n    tx: mpsc::UnboundedSender<InMemoryResponseStreamItem>,\n}\n\nimpl ServerSendStream for InMemoryServerSendStream {\n    async fn send<'a>(\n        &mut self,\n        item: crate::core::ServerResponseStreamItem<'a>,\n        _options: ServerSendOptions,\n    ) -> Result<(), ()> {\n        let inmemory_item = match item {\n            ResponseStreamItem::Headers(h) => InMemoryResponseStreamItem::Headers(h),\n            ResponseStreamItem::Message(m) => {\n                let buf = m.encode().map_err(|_| ())?;\n                InMemoryResponseStreamItem::Message(buf)\n            }\n            ResponseStreamItem::Trailers(t) => InMemoryResponseStreamItem::Trailers(t),\n            ResponseStreamItem::StreamClosed => InMemoryResponseStreamItem::StreamClosed,\n        };\n\n        self.tx.send(inmemory_item).map_err(|_| ())\n    }\n}\n\npub struct InMemoryServerRecvStream {\n    rx: mpsc::UnboundedReceiver<InMemoryRequestStreamItem>,\n}\n\nimpl ServerRecvStream for InMemoryServerRecvStream {\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> Result<(), ()> {\n        match self.rx.recv().await {\n            Some(InMemoryRequestStreamItem::Message(mut buf)) => {\n                msg.decode(&mut buf).map_err(|_| ())\n            }\n            _ => Err(()),\n        }\n    }\n}\n\npub struct InMemoryConnection {\n    s: mpsc::Sender<InMemoryServerCall>,\n    closed_tx: Option<oneshot::Sender<Result<(), String>>>,\n}\n\nimpl Invoke for InMemoryConnection {\n    type SendStream = Box<dyn ClientDynSendStream>;\n    type RecvStream = Box<dyn ClientDynRecvStream>;\n\n    async fn invoke(\n        &self,\n        headers: RequestHeaders,\n        _options: CallOptions,\n    ) -> (Self::SendStream, Self::RecvStream) {\n        let (req_tx, req_rx) = mpsc::unbounded_channel::<InMemoryRequestStreamItem>();\n        let (resp_tx, resp_rx) = mpsc::unbounded_channel::<InMemoryResponseStreamItem>();\n\n        let call = InMemoryServerCall {\n            headers,\n            req_rx,\n            resp_tx,\n        };\n\n        let _ = self.s.try_send(call);\n\n        (\n            Box::new(InMemoryClientSendStream { tx: Some(req_tx) }),\n            Box::new(InMemoryClientRecvStream { rx: resp_rx }),\n        )\n    }\n}\nimpl Drop for InMemoryConnection {\n    fn drop(&mut self) {\n        let _ = self.closed_tx.take().unwrap().send(Err(\"\".into()));\n    }\n}\n\npub struct InMemoryClientSendStream {\n    tx: Option<mpsc::UnboundedSender<InMemoryRequestStreamItem>>,\n}\n\nimpl ClientSendStream for InMemoryClientSendStream {\n    async fn send(&mut self, msg: &dyn SendMessage, _options: ClientSendOptions) -> Result<(), ()> {\n        let buf = msg.encode().unwrap();\n\n        if self\n            .tx\n            .as_mut()\n            .unwrap()\n            .send(InMemoryRequestStreamItem::Message(buf))\n            .is_err()\n        {\n            self.tx = None;\n            return Err(());\n        }\n        Ok(())\n    }\n}\n\nimpl Drop for InMemoryClientSendStream {\n    fn drop(&mut self) {\n        if let Some(tx) = self.tx.take() {\n            let _ = tx.send(InMemoryRequestStreamItem::StreamClosed);\n        }\n    }\n}\n\npub struct InMemoryClientRecvStream {\n    rx: mpsc::UnboundedReceiver<InMemoryResponseStreamItem>,\n}\n\nimpl ClientRecvStream for InMemoryClientRecvStream {\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> ClientResponseStreamItem {\n        match self.rx.recv().await {\n            Some(InMemoryResponseStreamItem::Headers(h)) => ClientResponseStreamItem::Headers(h),\n            Some(InMemoryResponseStreamItem::Message(mut buf)) => {\n                msg.decode(&mut buf).unwrap();\n                ClientResponseStreamItem::Message(())\n            }\n            Some(InMemoryResponseStreamItem::Trailers(t)) => ClientResponseStreamItem::Trailers(t),\n            _ => ClientResponseStreamItem::StreamClosed,\n        }\n    }\n}\n\npub struct InMemoryTransport {}\n\nimpl Transport for InMemoryTransport {\n    type Service = InMemoryConnection;\n\n    async fn connect(\n        &self,\n        target: String,\n        _runtime: GrpcRuntime,\n        _options: &TransportOptions,\n    ) -> Result<(Self::Service, oneshot::Receiver<Result<(), String>>), String> {\n        let listeners = LISTENERS.lock().unwrap();\n        let s = listeners\n            .get(&target)\n            .ok_or_else(|| format!(\"no listener for target: {}\", target))?;\n\n        let (closed_tx, closed_rx) = oneshot::channel();\n        let conn = InMemoryConnection {\n            s: s.clone(),\n            closed_tx: Some(closed_tx),\n        };\n\n        Ok((conn, closed_rx))\n    }\n}\n\npub struct InMemoryResolverBuilder {}\n\nimpl ResolverBuilder for InMemoryResolverBuilder {\n    fn build(&self, target: &Target, options: ResolverOptions) -> Box<dyn Resolver> {\n        let path = target.path().strip_prefix('/').unwrap_or(target.path());\n        let ids: Vec<String> = path.split(',').map(|s| s.to_string()).collect();\n        options.work_scheduler.schedule_work();\n        Box::new(InMemoryResolver { ids })\n    }\n\n    fn scheme(&self) -> &str {\n        \"inmemory\"\n    }\n\n    fn is_valid_uri(&self, _uri: &Target) -> bool {\n        true\n    }\n}\n\nstruct InMemoryResolver {\n    ids: Vec<String>,\n}\n\nimpl Resolver for InMemoryResolver {\n    fn resolve_now(&mut self) {}\n\n    fn work(&mut self, channel_controller: &mut dyn ResolverChannelController) {\n        let endpoints = self\n            .ids\n            .iter()\n            .map(|id| Endpoint {\n                addresses: vec![Address {\n                    network_type: \"inmemory\",\n                    address: crate::byte_str::ByteStr::from(id.clone()),\n                    ..Default::default()\n                }],\n                ..Default::default()\n            })\n            .collect();\n\n        let _ = channel_controller.update(ResolverUpdate {\n            endpoints: Ok(endpoints),\n            service_config: Ok(Some(ServiceConfig {\n                load_balancing_policy: Some(\n                    crate::client::service_config::LbPolicyType::RoundRobin,\n                ),\n            })),\n            ..Default::default()\n        });\n    }\n}\n\npub fn reg() {\n    GLOBAL_TRANSPORT_REGISTRY.add_transport(\"inmemory\", InMemoryTransport {});\n    global_resolver_registry().add_builder(Box::new(InMemoryResolverBuilder {}));\n}\n"
  },
  {
    "path": "grpc/src/lib.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\n//! The official Rust implementation of [gRPC], a high performance, open source,\n//! universal RPC framework\n//!\n//! This version is in progress and not recommended for any production use.  All\n//! APIs are unstable.  Proceed at your own risk.\n//!\n//! [gRPC]: https://grpc.io\n#![allow(dead_code, unused_variables)]\n\npub mod client;\npub mod core;\npub mod credentials;\npub mod inmemory;\npub mod server;\n\nmod macros;\nmod status;\n\npub use status::ServerStatus;\npub use status::Status;\npub use status::StatusCode;\n\nmod attributes;\nmod byte_str;\nmod rt;\nmod send_future;\n\n#[cfg(test)]\nmod echo_pb {\n    include!(concat!(\n        env!(\"CARGO_MANIFEST_DIR\"),\n        \"/src/generated/grpc_examples_echo.rs\"\n    ));\n}\n"
  },
  {
    "path": "grpc/src/macros.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\n/// Includes generated proto message, client, and server code.\n///\n/// You must specify the path to the `.proto` file **relative to the proto root\n/// directory**,  without the `.proto` extension.  \n///\n/// For example, if your proto directory is `path/to/protos` and it contains the\n/// file  `helloworld.proto`, you would write:\n///\n/// ```rust,ignore\n/// mod pb {\n///     grpc::include_proto!(\"path/to/protos\", \"helloworld\");\n/// }\n/// ```\n///\n/// # Note\n/// **This macro only works if the gRPC build output directory and message path\n/// are unmodified.** By default:\n/// - The output directory is set to the [`OUT_DIR`] environment variable.\n/// - The message path is set to `self`.\n///\n/// If your `.proto` files are not in a subdirectory, you can omit the first\n/// parameter.\n///\n/// ```rust,ignore\n/// mod pb {\n///     grpc::include_proto!(\"helloworld\");\n/// }\n/// ```\n///\n/// If you have modified the output directory or message path, you should use\n/// the include_generated_code macro below instead of using this macro or\n/// manually include it yourself.\n///\n/// ```rust,ignore\n/// mod grpc {\n///     grpc::include_generated_proto!(\"path/to/protos\", \"helloworld\");\n/// }\n/// ```\n///\n/// The following example assumes the message code is imported using `self`:\n///\n/// ```rust,ignore\n/// mod protos {\n///     // Include message code.\n///     include!(\"relative/protobuf/directory/generated.rs\");\n///\n///     // Include service code.\n///     include!(\"relative/protobuf/directory/helloworld_grpc.pb.rs\");\n/// }\n/// ```\n///\n/// If the message code and service code are in different modules, and the\n/// message path specified during code generation is `super::protos`, use:\n///\n/// ```rust,ignore\n/// mod protos {\n///     // Include message code.\n///     include!(\"relative/protobuf/directory/generated.rs\");\n/// }\n///\n/// mod grpc {\n///     // Include service code.\n///     include!(\"relative/protobuf/directory/helloworld_grpc.pb.rs\");\n/// }\n/// ```\n///\n/// [`OUT_DIR`]:\n///     https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts\n#[macro_export]\nmacro_rules! include_proto {\n    // Assume the generated output dir is OUT_DIR.\n    ($proto_file:literal) => {\n        $crate::include_proto!(\"\", $proto_file);\n    };\n\n    ($parent_dir:literal, $proto_file:literal) => {\n        include!(concat!(env!(\"OUT_DIR\"), \"/\", $parent_dir, \"/generated.rs\"));\n        include!(concat!(\n            env!(\"OUT_DIR\"),\n            \"/\",\n            $parent_dir,\n            \"/\",\n            $proto_file,\n            \"_grpc.pb.rs\"\n        ));\n    };\n}\n\n/// Includes generated proto message, client, and server code. This macro is for\n/// if you manually set output_dir instead of using the default OUT_DIR.\n///\n/// You must specify the path to the `.proto` file **relative to the proto root\n/// directory**,  without the `.proto` extension.  \n///\n/// For example, if your proto directory is `path/to/protos` and it contains the\n/// file  `helloworld.proto`, you would write:\n///\n/// ```rust,ignore\n/// mod pb {\n///     grpc::include_generated_proto!(\"path/to/protos\", \"helloworld\");\n/// }\n/// ```\n///\n/// If your `.proto` files are not in a subdirectory, you can omit the first\n/// parameter.\n///\n/// ```rust,ignore\n/// mod pb {\n///     grpc::include_generated_proto!(\"helloworld\");\n/// }\n/// ```\n///\n/// [`CARGO_MANIFEST_DIR`]:\n///     https://doc.rust-lang.org/cargo/reference/environment-variables.html\n#[macro_export]\nmacro_rules! include_generated_proto {\n    ($proto_file:literal) => {\n        $crate::include_generated_proto!(\"\", $proto_file);\n    };\n\n    ($parent_dir:literal, $proto_file:literal) => {\n        include!(concat!(\n            env!(\"CARGO_MANIFEST_DIR\"),\n            \"/\",\n            $parent_dir,\n            \"/generated.rs\"\n        ));\n        include!(concat!(\n            env!(\"CARGO_MANIFEST_DIR\"),\n            \"/\",\n            $parent_dir,\n            \"/\",\n            $proto_file,\n            \"_grpc.pb.rs\"\n        ));\n    };\n}\n"
  },
  {
    "path": "grpc/src/rt/hyper_wrapper.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::future::Future;\nuse std::io;\nuse std::pin::Pin;\nuse std::task::Context;\nuse std::task::Poll;\nuse std::time::Instant;\n\nuse hyper::rt::Executor;\nuse hyper::rt::Timer;\nuse pin_project_lite::pin_project;\nuse tokio::io::AsyncRead;\nuse tokio::io::AsyncWrite;\nuse tokio::io::ReadBuf;\n\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::GrpcRuntime;\n\n/// Adapts a runtime to a hyper compatible executor.\n#[derive(Clone)]\npub(crate) struct HyperCompatExec {\n    pub(crate) inner: GrpcRuntime,\n}\n\nimpl<F> Executor<F> for HyperCompatExec\nwhere\n    F: Future + Send + 'static,\n    F::Output: Send + 'static,\n{\n    fn execute(&self, fut: F) {\n        self.inner.spawn(Box::pin(async {\n            let _ = fut.await;\n        }));\n    }\n}\n\nstruct HyperCompatSleep {\n    inner: Pin<Box<dyn super::Sleep>>,\n}\n\nimpl Future for HyperCompatSleep {\n    type Output = ();\n\n    fn poll(\n        mut self: Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Self::Output> {\n        self.inner.as_mut().poll(cx)\n    }\n}\n\nimpl hyper::rt::Sleep for HyperCompatSleep {}\n\n/// Adapts a runtime to a hyper compatible timer.\npub(crate) struct HyperCompatTimer {\n    pub(crate) inner: GrpcRuntime,\n}\n\nimpl Timer for HyperCompatTimer {\n    fn sleep(&self, duration: std::time::Duration) -> Pin<Box<dyn hyper::rt::Sleep>> {\n        let sleep = self.inner.sleep(duration);\n        Box::pin(HyperCompatSleep { inner: sleep })\n    }\n\n    fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn hyper::rt::Sleep>> {\n        let now = Instant::now();\n        let duration = deadline.saturating_duration_since(now);\n        self.sleep(duration)\n    }\n}\n\n// The following adapters are copied from hyper:\n// https://github.com/hyperium/hyper/blob/v1.6.0/benches/support/tokiort.rs\n\npin_project! {\n    /// A wrapper to make any `GrpcEndpoint` compatible with Hyper. It implements\n    /// Tokio's async IO traits.\n    pub(crate) struct HyperStream {\n        #[pin]\n        inner: Box<dyn GrpcEndpoint>,\n    }\n}\n\nimpl HyperStream {\n    /// Creates a new `HyperStream` from a type implementing `TcpStream`.\n    pub fn new(stream: Box<dyn GrpcEndpoint>) -> Self {\n        Self { inner: stream }\n    }\n}\n\nimpl AsyncRead for HyperStream {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &mut ReadBuf<'_>,\n    ) -> Poll<io::Result<()>> {\n        // Delegate the poll_read call to the inner stream.\n        Pin::new(&mut self.inner).poll_read(cx, buf)\n    }\n}\n\nimpl AsyncWrite for HyperStream {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<io::Result<usize>> {\n        Pin::new(&mut self.inner).poll_write(cx, buf)\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.inner).poll_flush(cx)\n    }\n\n    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.inner).poll_shutdown(cx)\n    }\n}\n\nimpl hyper::rt::Read for HyperStream {\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        mut buf: hyper::rt::ReadBufCursor<'_>,\n    ) -> Poll<Result<(), io::Error>> {\n        let n = unsafe {\n            let mut tbuf = tokio::io::ReadBuf::uninit(buf.as_mut());\n            match tokio::io::AsyncRead::poll_read(self.project().inner, cx, &mut tbuf) {\n                Poll::Ready(Ok(())) => tbuf.filled().len(),\n                other => return other,\n            }\n        };\n\n        unsafe {\n            buf.advance(n);\n        }\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl hyper::rt::Write for HyperStream {\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, io::Error>> {\n        AsyncWrite::poll_write(self.project().inner, cx, buf)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {\n        AsyncWrite::poll_flush(self.project().inner, cx)\n    }\n\n    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {\n        AsyncWrite::poll_shutdown(self.project().inner, cx)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        AsyncWrite::is_write_vectored(&self.inner)\n    }\n\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[io::IoSlice<'_>],\n    ) -> Poll<Result<usize, io::Error>> {\n        AsyncWrite::poll_write_vectored(self.project().inner, cx, bufs)\n    }\n}\n"
  },
  {
    "path": "grpc/src/rt/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::fmt::Debug;\nuse std::future::Future;\nuse std::net::SocketAddr;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::time::Duration;\n\npub(crate) mod hyper_wrapper;\n#[cfg(feature = \"_runtime-tokio\")]\npub(crate) mod tokio;\n\npub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;\npub type BoxedTaskHandle = Box<dyn TaskHandle>;\npub type BoxEndpoint = Box<dyn GrpcEndpoint>;\npub type ScopedBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;\n\n/// An abstraction over an asynchronous runtime.\n///\n/// The `Runtime` trait defines the core functionality required for\n/// executing asynchronous tasks, creating DNS resolvers, and performing\n/// time-based operations such as sleeping. It provides a uniform interface\n/// that can be implemented for various async runtimes, enabling pluggable\n/// and testable infrastructure.\npub trait Runtime: Send + Sync + Debug {\n    /// Spawns the given asynchronous task to run in the background.\n    fn spawn(&self, task: Pin<Box<dyn Future<Output = ()> + Send + 'static>>) -> BoxedTaskHandle;\n\n    /// Creates and returns an instance of a DNSResolver, optionally\n    /// configured by the ResolverOptions struct. This method may return an\n    /// error if it fails to create the DNSResolver.\n    fn get_dns_resolver(&self, opts: ResolverOptions) -> Result<Box<dyn DnsResolver>, String>;\n\n    /// Returns a future that completes after the specified duration.\n    fn sleep(&self, duration: std::time::Duration) -> Pin<Box<dyn Sleep>>;\n\n    /// Establishes a TCP connection to the given `target` address with the\n    /// specified `opts`.\n    fn tcp_stream(\n        &self,\n        target: SocketAddr,\n        opts: TcpOptions,\n    ) -> BoxFuture<Result<Box<dyn GrpcEndpoint>, String>>;\n\n    /// Create a new listener for the given address.\n    fn listen_tcp(\n        &self,\n        addr: SocketAddr,\n        opts: TcpOptions,\n    ) -> BoxFuture<Result<Box<dyn TcpListener>, String>>;\n}\n\n/// A future that resolves after a specified duration.\npub trait Sleep: Send + Sync + Future<Output = ()> {}\n\npub trait TaskHandle: Send + Sync {\n    /// Abort the associated task.\n    fn abort(&self);\n}\n\n/// A trait for asynchronous DNS resolution.\n#[tonic::async_trait]\npub trait DnsResolver: Send + Sync {\n    /// Resolve an address\n    async fn lookup_host_name(&self, name: &str) -> Result<Vec<std::net::IpAddr>, String>;\n    /// Perform a TXT record lookup. If a txt record contains multiple strings,\n    /// they are concatenated.\n    async fn lookup_txt(&self, name: &str) -> Result<Vec<String>, String>;\n}\n\n#[derive(Default)]\npub struct ResolverOptions {\n    /// The address of the DNS server in \"IP:port\" format. If None, the\n    /// system's default DNS server will be used.\n    pub(super) server_addr: Option<std::net::SocketAddr>,\n}\n\n#[derive(Default)]\npub struct TcpOptions {\n    pub(crate) enable_nodelay: bool,\n    pub(crate) keepalive: Option<Duration>,\n}\n\npub(crate) mod endpoint {\n    /// This trait is sealed since we may need to change the read and write\n    /// methods to align closely with the gRPC C++ implementations. For example,\n    /// the read method may be responsible for allocating the buffer and\n    /// returning it to enable in-place decryption. Since the libraries used\n    /// for http2 and channel credentials use AsyncRead, designing such an API\n    /// today would require adapters which would incur an extra copy, affecting\n    /// performance.\n    pub trait Sealed: tokio::io::AsyncRead + tokio::io::AsyncWrite {}\n}\n\n/// GrpcEndpoint is a generic stream-oriented network connection.\npub trait GrpcEndpoint: endpoint::Sealed + Send + Unpin + 'static {\n    /// Returns the local address that this stream is bound to.\n    fn get_local_address(&self) -> &str;\n\n    /// Returns the remote address that this stream is connected to.\n    fn get_peer_address(&self) -> &str;\n\n    fn get_network_type(&self) -> &'static str;\n}\n\nimpl endpoint::Sealed for Box<dyn GrpcEndpoint> {}\nimpl GrpcEndpoint for Box<dyn GrpcEndpoint> {\n    fn get_local_address(&self) -> &str {\n        (**self).get_local_address()\n    }\n\n    fn get_peer_address(&self) -> &str {\n        (**self).get_peer_address()\n    }\n\n    fn get_network_type(&self) -> &'static str {\n        (**self).get_network_type()\n    }\n}\n\n/// A trait representing a TCP listener capable of accepting incoming\n/// connections.\npub trait TcpListener: Send + Sync {\n    /// Accepts a new incoming connection.\n    ///\n    /// Returns a future that resolves to a result containing the new\n    /// `GrpcEndpoint` and the remote peer's `SocketAddr`, or an error string\n    /// if acceptance fails.\n    fn accept(&mut self) -> ScopedBoxFuture<'_, Result<(BoxEndpoint, SocketAddr), String>>;\n\n    /// Returns the local socket address this listener is bound to.\n    fn local_addr(&self) -> &SocketAddr;\n}\n\n/// A fake runtime to satisfy the compiler when no runtime is enabled. This will\n///\n/// # Panics\n///\n/// Panics if any of its functions are called.\n#[derive(Default, Debug)]\npub(crate) struct NoOpRuntime {}\n\nimpl Runtime for NoOpRuntime {\n    fn spawn(&self, task: Pin<Box<dyn Future<Output = ()> + Send + 'static>>) -> BoxedTaskHandle {\n        unimplemented!()\n    }\n\n    fn get_dns_resolver(&self, opts: ResolverOptions) -> Result<Box<dyn DnsResolver>, String> {\n        unimplemented!()\n    }\n\n    fn sleep(&self, duration: std::time::Duration) -> Pin<Box<dyn Sleep>> {\n        unimplemented!()\n    }\n\n    fn tcp_stream(\n        &self,\n        target: SocketAddr,\n        opts: TcpOptions,\n    ) -> Pin<Box<dyn Future<Output = Result<Box<dyn GrpcEndpoint>, String>> + Send>> {\n        unimplemented!()\n    }\n\n    fn listen_tcp(\n        &self,\n        addr: SocketAddr,\n        _opts: TcpOptions,\n    ) -> BoxFuture<Result<Box<dyn TcpListener>, String>> {\n        unimplemented!()\n    }\n}\n\npub(crate) fn default_runtime() -> GrpcRuntime {\n    #[cfg(feature = \"_runtime-tokio\")]\n    {\n        return GrpcRuntime::new(tokio::TokioRuntime::default());\n    }\n    #[allow(unreachable_code)]\n    GrpcRuntime::new(NoOpRuntime::default())\n}\n\n#[derive(Clone, Debug)]\npub struct GrpcRuntime {\n    inner: Arc<dyn Runtime>,\n}\n\nimpl GrpcRuntime {\n    pub fn new<T: Runtime + 'static>(runtime: T) -> Self {\n        GrpcRuntime {\n            inner: Arc::new(runtime),\n        }\n    }\n\n    pub fn spawn(\n        &self,\n        task: Pin<Box<dyn Future<Output = ()> + Send + 'static>>,\n    ) -> BoxedTaskHandle {\n        self.inner.spawn(task)\n    }\n\n    pub fn get_dns_resolver(&self, opts: ResolverOptions) -> Result<Box<dyn DnsResolver>, String> {\n        self.inner.get_dns_resolver(opts)\n    }\n\n    pub fn sleep(&self, duration: std::time::Duration) -> Pin<Box<dyn Sleep>> {\n        self.inner.sleep(duration)\n    }\n\n    pub fn tcp_stream(\n        &self,\n        target: SocketAddr,\n        opts: TcpOptions,\n    ) -> BoxFuture<Result<Box<dyn GrpcEndpoint>, String>> {\n        self.inner.tcp_stream(target, opts)\n    }\n\n    pub fn listen_tcp(\n        &self,\n        addr: SocketAddr,\n        opts: TcpOptions,\n    ) -> BoxFuture<Result<Box<dyn TcpListener>, String>> {\n        self.inner.listen_tcp(addr, opts)\n    }\n}\n"
  },
  {
    "path": "grpc/src/rt/tokio/hickory_resolver.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::net::IpAddr;\n\nuse hickory_resolver::TokioResolver;\nuse hickory_resolver::config::LookupIpStrategy;\nuse hickory_resolver::config::NameServerConfigGroup;\nuse hickory_resolver::config::ResolverConfig;\nuse hickory_resolver::config::ResolverOpts;\nuse hickory_resolver::name_server::TokioConnectionProvider;\n\nuse crate::rt::ResolverOptions;\nuse crate::rt::{self};\n\n/// A DNS resolver that uses hickory with the tokio runtime. This supports txt\n/// lookups in addition to A and AAAA record lookups. It also supports using\n/// custom DNS servers.\npub(super) struct DnsResolver {\n    resolver: hickory_resolver::TokioResolver,\n}\n\n#[tonic::async_trait]\nimpl rt::DnsResolver for DnsResolver {\n    async fn lookup_host_name(&self, name: &str) -> Result<Vec<IpAddr>, String> {\n        let response = self\n            .resolver\n            .lookup_ip(name)\n            .await\n            .map_err(|err| err.to_string())?;\n        Ok(response.iter().collect())\n    }\n\n    async fn lookup_txt(&self, name: &str) -> Result<Vec<String>, String> {\n        let response: Vec<_> = self\n            .resolver\n            .txt_lookup(name)\n            .await\n            .map_err(|err| err.to_string())?\n            .iter()\n            .map(|txt_record| {\n                txt_record\n                    .iter()\n                    .map(|bytes| String::from_utf8_lossy(bytes).into_owned())\n                    .collect::<Vec<String>>()\n                    .join(\"\")\n            })\n            .collect();\n        Ok(response)\n    }\n}\n\nimpl DnsResolver {\n    pub(super) fn new(opts: ResolverOptions) -> Result<Self, String> {\n        let builder = if let Some(server_addr) = opts.server_addr {\n            let provider = TokioConnectionProvider::default();\n            let name_servers = NameServerConfigGroup::from_ips_clear(\n                &[server_addr.ip()],\n                server_addr.port(),\n                true,\n            );\n            let config = ResolverConfig::from_parts(None, vec![], name_servers);\n            TokioResolver::builder_with_config(config, provider)\n        } else {\n            TokioResolver::builder_tokio().map_err(|err| err.to_string())?\n        };\n        let mut resolver_opts = ResolverOpts::default();\n        resolver_opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;\n        Ok(DnsResolver {\n            resolver: builder.with_options(resolver_opts).build(),\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::net::Ipv4Addr;\n    use std::net::SocketAddr;\n    use std::sync::Arc;\n\n    use hickory_resolver::Name;\n    use hickory_server::ServerFuture;\n    use hickory_server::authority::Catalog;\n    use hickory_server::authority::ZoneType;\n    use hickory_server::proto::rr::LowerName;\n    use hickory_server::proto::rr::RData;\n    use hickory_server::proto::rr::Record;\n    use hickory_server::proto::rr::rdata::A;\n    use hickory_server::proto::rr::rdata::TXT;\n    use hickory_server::store::in_memory::InMemoryAuthority;\n    use tokio::net::UdpSocket;\n    use tokio::sync::oneshot;\n    use tokio::task::JoinHandle;\n\n    use crate::rt::DnsResolver;\n    use crate::rt::ResolverOptions;\n    use crate::rt::tokio::TokioDefaultDnsResolver;\n\n    #[tokio::test]\n    async fn compare_hickory_and_default() {\n        let hickory_dns = super::DnsResolver::new(ResolverOptions::default()).unwrap();\n        let mut ips_hickory = hickory_dns.lookup_host_name(\"localhost\").await.unwrap();\n\n        let default_resolver = TokioDefaultDnsResolver::new(ResolverOptions::default()).unwrap();\n\n        let mut system_resolver_ips = default_resolver\n            .lookup_host_name(\"localhost\")\n            .await\n            .unwrap();\n\n        // Hickory requests A and AAAA records in parallel, so the order of IPv4\n        // and IPv6 addresses isn't deterministic.\n        ips_hickory.sort();\n        system_resolver_ips.sort();\n        assert_eq!(\n            ips_hickory, system_resolver_ips,\n            \"both resolvers should produce same IPs for localhost\"\n        )\n    }\n\n    #[tokio::test]\n    async fn resolve_txt() {\n        let records = vec![\n            Record::from_rdata(\n                Name::from_ascii(\"test.local.\").unwrap(),\n                300,\n                RData::TXT(TXT::new(vec![\n                    \"one\".to_string(),\n                    \"two\".to_string(),\n                    \"three\".to_string(),\n                ])),\n            ),\n            Record::from_rdata(\n                Name::from_ascii(\"test.local.\").unwrap(),\n                300,\n                RData::TXT(TXT::new(vec![\n                    \"abc\".to_string(),\n                    \"def\".to_string(),\n                    \"ghi\".to_string(),\n                ])),\n            ),\n        ];\n\n        let dns = start_in_memory_dns_server(\"test.local.\", records).await;\n        let opts = ResolverOptions {\n            server_addr: Some(dns.addr),\n        };\n        let hickory_dns = super::DnsResolver::new(opts).unwrap();\n\n        let txt = hickory_dns.lookup_txt(\"test.local\").await.unwrap();\n        assert_eq!(\n            txt,\n            vec![\"onetwothree\".to_string(), \"abcdefghi\".to_string(),]\n        );\n        dns.shutdown().await;\n    }\n\n    #[tokio::test]\n    async fn custom_authority() {\n        let record = Record::from_rdata(\n            Name::from_ascii(\"test.local.\").unwrap(),\n            300,\n            RData::A(A(Ipv4Addr::new(1, 2, 3, 4))),\n        );\n        let dns = start_in_memory_dns_server(\"test.local.\", vec![record]).await;\n        let opts = ResolverOptions {\n            server_addr: Some(dns.addr),\n        };\n        let hickory_dns = super::DnsResolver::new(opts).unwrap();\n        let ips = hickory_dns.lookup_host_name(\"test.local\").await.unwrap();\n        assert_eq!(ips, vec![Ipv4Addr::new(1, 2, 3, 4)]);\n        dns.shutdown().await\n    }\n\n    struct FakeDns {\n        tx: Option<oneshot::Sender<()>>,\n        join_handle: Option<JoinHandle<()>>,\n        addr: SocketAddr,\n    }\n\n    impl FakeDns {\n        async fn shutdown(mut self) {\n            let tx = self.tx.take().unwrap();\n            tx.send(()).unwrap();\n            let handle = self.join_handle.take().unwrap();\n            handle.await.unwrap();\n        }\n    }\n\n    /// Starts an in-memory DNS server with and adds the given records. Returns\n    /// a DNS server which should be shutdown after the test. It uses a random\n    /// port to bind since tests can run in parallel. The assigned port can be\n    /// read from the returned struct.\n    async fn start_in_memory_dns_server(host: &str, records: Vec<Record>) -> FakeDns {\n        // Create a simple A record for `test.local.`\n        let authority =\n            InMemoryAuthority::empty(Name::from_ascii(host).unwrap(), ZoneType::Primary, false);\n\n        for record in records {\n            authority.upsert(record, 0).await;\n        }\n\n        let mut catalog = Catalog::new();\n        catalog.upsert(\n            LowerName::new(&Name::from_ascii(host).unwrap()),\n            vec![Arc::new(authority)],\n        );\n\n        let mut server = ServerFuture::new(catalog);\n\n        let socket = UdpSocket::bind(\"127.0.0.1:0\").await.unwrap();\n        let addr = socket.local_addr().unwrap();\n        server.register_socket(socket);\n\n        println!(\"DNS server running on {addr}\");\n\n        let (tx, rx) = oneshot::channel::<()>();\n        let server_task = tokio::spawn(async move {\n            tokio::select! {\n                _ = server.block_until_done() => {},\n                _ = rx => {\n                    server.shutdown_gracefully().await.unwrap();\n                }\n            }\n        });\n        FakeDns {\n            tx: Some(tx),\n            join_handle: Some(server_task),\n            addr,\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/rt/tokio/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::future::Future;\nuse std::net::IpAddr;\nuse std::net::SocketAddr;\nuse std::pin::Pin;\nuse std::time::Duration;\n\nuse tokio::io::AsyncRead;\nuse tokio::io::AsyncWrite;\nuse tokio::net::TcpStream;\nuse tokio::task::JoinHandle;\n\nuse crate::client::name_resolution::TCP_IP_NETWORK_TYPE;\nuse crate::rt::BoxEndpoint;\nuse crate::rt::BoxFuture;\nuse crate::rt::BoxedTaskHandle;\nuse crate::rt::DnsResolver;\nuse crate::rt::GrpcEndpoint;\nuse crate::rt::ResolverOptions;\nuse crate::rt::Runtime;\nuse crate::rt::ScopedBoxFuture;\nuse crate::rt::Sleep;\nuse crate::rt::TaskHandle;\nuse crate::rt::TcpOptions;\nuse crate::rt::endpoint;\n\n#[cfg(feature = \"dns\")]\nmod hickory_resolver;\n\n/// A DNS resolver that uses tokio::net::lookup_host for resolution. It only\n/// supports host lookups.\nstruct TokioDefaultDnsResolver {\n    _priv: (),\n}\n\n#[tonic::async_trait]\nimpl DnsResolver for TokioDefaultDnsResolver {\n    async fn lookup_host_name(&self, name: &str) -> Result<Vec<IpAddr>, String> {\n        let name_with_port = match name.parse::<IpAddr>() {\n            Ok(ip) => SocketAddr::new(ip, 0).to_string(),\n            Err(_) => format!(\"{name}:0\"),\n        };\n        let ips = tokio::net::lookup_host(name_with_port)\n            .await\n            .map_err(|err| err.to_string())?\n            .map(|socket_addr| socket_addr.ip())\n            .collect();\n        Ok(ips)\n    }\n\n    async fn lookup_txt(&self, _name: &str) -> Result<Vec<String>, String> {\n        Err(\"TXT record lookup unavailable. Enable the optional 'dns' feature to enable service config lookups.\".to_string())\n    }\n}\n\n#[derive(Debug, Default)]\npub(crate) struct TokioRuntime {\n    _priv: (),\n}\n\nimpl TaskHandle for JoinHandle<()> {\n    fn abort(&self) {\n        self.abort()\n    }\n}\n\nimpl Sleep for tokio::time::Sleep {}\n\nimpl Runtime for TokioRuntime {\n    fn spawn(&self, task: Pin<Box<dyn Future<Output = ()> + Send + 'static>>) -> BoxedTaskHandle {\n        Box::new(tokio::spawn(task))\n    }\n\n    fn get_dns_resolver(&self, opts: ResolverOptions) -> Result<Box<dyn DnsResolver>, String> {\n        #[cfg(feature = \"dns\")]\n        {\n            Ok(Box::new(hickory_resolver::DnsResolver::new(opts)?))\n        }\n        #[cfg(not(feature = \"dns\"))]\n        {\n            Ok(Box::new(TokioDefaultDnsResolver::new(opts)?))\n        }\n    }\n\n    fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {\n        Box::pin(tokio::time::sleep(duration))\n    }\n\n    fn tcp_stream(\n        &self,\n        target: SocketAddr,\n        opts: super::TcpOptions,\n    ) -> Pin<Box<dyn Future<Output = Result<Box<dyn super::GrpcEndpoint>, String>> + Send>> {\n        Box::pin(async move {\n            let stream = TcpStream::connect(target)\n                .await\n                .map_err(|err| err.to_string())?;\n            if let Some(duration) = opts.keepalive {\n                let sock_ref = socket2::SockRef::from(&stream);\n                let mut ka = socket2::TcpKeepalive::new();\n                ka = ka.with_time(duration);\n                sock_ref\n                    .set_tcp_keepalive(&ka)\n                    .map_err(|err| err.to_string())?;\n            }\n            let stream: Box<dyn super::GrpcEndpoint> = Box::new(TokioTcpStream {\n                peer_addr: target.to_string().into_boxed_str(),\n                local_addr: stream\n                    .local_addr()\n                    .map_err(|err| err.to_string())?\n                    .to_string()\n                    .into_boxed_str(),\n                inner: stream,\n            });\n            Ok(stream)\n        })\n    }\n\n    fn listen_tcp(\n        &self,\n        addr: SocketAddr,\n        _opts: TcpOptions,\n    ) -> BoxFuture<Result<Box<dyn super::TcpListener>, String>> {\n        Box::pin(async move {\n            let listener = tokio::net::TcpListener::bind(addr)\n                .await\n                .map_err(|err| err.to_string())?;\n            let local_addr = listener.local_addr().map_err(|e| e.to_string())?;\n            let listener = TokioListener {\n                inner: listener,\n                local_addr,\n            };\n            Ok(Box::new(listener) as Box<dyn super::TcpListener>)\n        })\n    }\n}\n\nimpl TokioDefaultDnsResolver {\n    pub fn new(opts: ResolverOptions) -> Result<Self, String> {\n        if opts.server_addr.is_some() {\n            return Err(\"Custom DNS server are not supported, enable optional feature 'dns' to enable support.\".to_string());\n        }\n        Ok(TokioDefaultDnsResolver { _priv: () })\n    }\n}\n\nstruct TokioTcpStream {\n    inner: TcpStream,\n    peer_addr: Box<str>,\n    local_addr: Box<str>,\n}\n\nimpl AsyncRead for TokioTcpStream {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n        buf: &mut tokio::io::ReadBuf<'_>,\n    ) -> std::task::Poll<std::io::Result<()>> {\n        Pin::new(&mut self.inner).poll_read(cx, buf)\n    }\n}\n\nimpl AsyncWrite for TokioTcpStream {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n        buf: &[u8],\n    ) -> std::task::Poll<Result<usize, std::io::Error>> {\n        Pin::new(&mut self.inner).poll_write(cx, buf)\n    }\n\n    fn poll_write_vectored(\n        mut self: Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n        bufs: &[std::io::IoSlice<'_>],\n    ) -> std::task::Poll<Result<usize, std::io::Error>> {\n        Pin::new(&mut self.inner).poll_write_vectored(cx, bufs)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        self.inner.is_write_vectored()\n    }\n\n    fn poll_flush(\n        mut self: Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Result<(), std::io::Error>> {\n        Pin::new(&mut self.inner).poll_flush(cx)\n    }\n\n    fn poll_shutdown(\n        mut self: Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Result<(), std::io::Error>> {\n        Pin::new(&mut self.inner).poll_shutdown(cx)\n    }\n}\n\nimpl endpoint::Sealed for TokioTcpStream {}\n\nimpl super::GrpcEndpoint for TokioTcpStream {\n    fn get_local_address(&self) -> &str {\n        &self.local_addr\n    }\n\n    fn get_peer_address(&self) -> &str {\n        &self.peer_addr\n    }\n\n    fn get_network_type(&self) -> &'static str {\n        TCP_IP_NETWORK_TYPE\n    }\n}\n\nstruct TokioListener {\n    inner: tokio::net::TcpListener,\n    local_addr: SocketAddr,\n}\n\nimpl super::TcpListener for TokioListener {\n    fn accept(&mut self) -> ScopedBoxFuture<'_, Result<(BoxEndpoint, SocketAddr), String>> {\n        Box::pin(async move {\n            let (stream, addr) = self.inner.accept().await.map_err(|e| e.to_string())?;\n            Ok((\n                Box::new(TokioTcpStream {\n                    local_addr: stream\n                        .local_addr()\n                        .map_err(|err| err.to_string())?\n                        .to_string()\n                        .into_boxed_str(),\n                    peer_addr: addr.to_string().into_boxed_str(),\n                    inner: stream,\n                }) as Box<dyn GrpcEndpoint>,\n                addr,\n            ))\n        })\n    }\n\n    fn local_addr(&self) -> &SocketAddr {\n        &self.local_addr\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::DnsResolver;\n    use super::ResolverOptions;\n    use super::Runtime;\n    use super::TokioDefaultDnsResolver;\n    use super::TokioRuntime;\n\n    #[tokio::test]\n    async fn lookup_hostname() {\n        let runtime = TokioRuntime::default();\n\n        let dns = runtime\n            .get_dns_resolver(ResolverOptions::default())\n            .unwrap();\n        let ips = dns.lookup_host_name(\"localhost\").await.unwrap();\n        assert!(\n            !ips.is_empty(),\n            \"Expect localhost to resolve to more than 1 IPs.\"\n        )\n    }\n\n    #[tokio::test]\n    async fn default_resolver_txt_fails() {\n        let default_resolver = TokioDefaultDnsResolver::new(ResolverOptions::default()).unwrap();\n\n        let txt = default_resolver.lookup_txt(\"google.com\").await;\n        assert!(txt.is_err())\n    }\n\n    #[tokio::test]\n    async fn default_resolver_custom_authority() {\n        let opts = ResolverOptions {\n            server_addr: Some(\"8.8.8.8:53\".parse().unwrap()),\n        };\n        let default_resolver = TokioDefaultDnsResolver::new(opts);\n        assert!(default_resolver.is_err())\n    }\n}\n"
  },
  {
    "path": "grpc/src/send_future.rs",
    "content": "/*\n *\n * Copyright 2026 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse core::future::Future;\n\n/// A helper trait to enforce and explicitly bound a [`Future`] as [`Send`].\n///\n/// This trait provides a mechanism to work around specific Rust compiler\n/// limitations and bugs where the compiler's borrow checker or drop analysis\n/// conservatively concludes that an `async` block is `!Send` (not safe to send\n/// across threads),\n/// even when it logically should be.\n///\n/// # Problem Context\n///\n/// As detailed in issues [#64552], [#102211], and [#96865], there are scenarios\n/// where:\n/// * An `async` function captures a reference to a type that is `!Sync`.\n/// * A variable is dropped before an `.await` point, but the compiler's liveness\n///   analysis incorrectly believes it is held across the await.\n/// * Complex control flow confuses the auto-trait deduction for `Send`.\n///\n/// These scenarios often result in obscure error messages when trying to spawn\n/// the future on an executor (like `tokio::spawn`), claiming the future is not\n/// `Send`.\n///\n/// # The Solution\n///\n/// The `make_send()` method acts as an identity function (a no-op at runtime) but\n/// performs two critical compile-time tasks:\n///\n/// 1.  **Explicit Assertion:** It requires `Self` to implement `Send` at the\n///     call site. This moves the error message from the deep internals of an\n///     executor's spawn function to the specific line where the future is created,\n///     making debugging significantly easier.\n/// 2.  **Type Erasure / Coercion:** By returning `impl Future<...> + Send`, it\n///     creates an opaque type boundary. This can sometimes help the compiler's\n///     trait solver \"lock in\" the `Send` guarantee and disregard phantom lifetime\n///     issues that might otherwise propagate.\n///\n/// [#64552]: https://github.com/rust-lang/rust/issues/64552\n/// [#102211]: https://github.com/rust-lang/rust/issues/102211\n/// [#96865]: https://github.com/rust-lang/rust/issues/96865\n/// [`Future`]: core::future::Future\n/// [`Send`]: core::marker::Send\npub trait SendFuture: Future {\n    /// Consumes the future and returns it as an opaque type that is guaranteed\n    /// to be [`Send`].\n    ///\n    /// This is a zero-cost abstraction (it simply returns `self`) used primarily\n    /// to help the compiler resolve auto-traits or to produce better error\n    /// diagnostics.\n    fn make_send(self) -> impl Future<Output = Self::Output> + Send\n    where\n        Self: Sized + Send,\n    {\n        self\n    }\n}\n\nimpl<T: Future> SendFuture for T {}\n"
  },
  {
    "path": "grpc/src/server/mod.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::sync::Arc;\n\nuse tonic::async_trait;\n\nuse crate::core::RecvMessage;\nuse crate::core::RequestHeaders;\nuse crate::core::ServerResponseStreamItem;\n\npub struct Server {\n    handler: Option<Arc<dyn DynHandle>>,\n}\n\npub struct Call<SS, RS> {\n    pub headers: RequestHeaders,\n    pub send: SS,\n    pub recv: RS,\n}\n\n#[trait_variant::make(Send)]\npub trait Listener {\n    type SendStream: SendStream + 'static;\n    type RecvStream: RecvStream + 'static;\n    async fn accept(&self) -> Option<Call<Self::SendStream, Self::RecvStream>>;\n}\n\nimpl Server {\n    pub fn new() -> Self {\n        Self { handler: None }\n    }\n\n    pub fn set_handler<H>(&mut self, h: H)\n    where\n        H: Handle + Send + Sync + 'static,\n    {\n        self.handler = Some(Arc::new(h))\n    }\n\n    pub async fn serve(&self, l: &impl Listener) {\n        while let Some(call) = l.accept().await {\n            let mut send: Box<dyn DynSendStream> = Box::new(call.send);\n            let recv: Box<dyn DynRecvStream> = Box::new(call.recv);\n            self.handler\n                .as_ref()\n                .unwrap()\n                .dyn_handle(call.headers, &mut *send, recv)\n                .await;\n        }\n    }\n}\n\nimpl Default for Server {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// A trait which may be implemented by types to handle server-side logic of\n/// RPCs (Remote Procedure Calls, often shortened to \"call\").\n#[trait_variant::make(Send)]\npub trait Handle: Send + Sync {\n    /// Handles an RPC, accepting the send and receive streams that are used to\n    /// interact with the call.  Note that `tx` is not static, so it cannot be\n    /// sent to another task, meaning the RPC must end before handle returns.\n    async fn handle(\n        &self,\n        headers: RequestHeaders,\n        tx: &mut impl SendStream,\n        rx: impl RecvStream + 'static,\n    );\n}\n\n#[async_trait]\ntrait DynHandle: Send + Sync {\n    async fn dyn_handle(\n        &self,\n        headers: RequestHeaders,\n        tx: &mut dyn DynSendStream,\n        rx: Box<dyn DynRecvStream>,\n    );\n}\n\n#[async_trait]\nimpl<T: Handle> DynHandle for T {\n    async fn dyn_handle(\n        &self,\n        headers: RequestHeaders,\n        mut tx: &mut dyn DynSendStream,\n        rx: Box<dyn DynRecvStream>,\n    ) {\n        self.handle(headers, &mut tx, rx).await\n    }\n}\n\n/// Represents the sending side of a server stream.  See `ResponseStream`\n/// documentation for information about the different types of items and the\n/// order in which they must be sent.\n#[trait_variant::make(Send)]\npub trait SendStream {\n    /// Sends the next item on the stream.\n    ///\n    /// # Cancel safety\n    ///\n    /// This method is not intended to be cancellation safe.  If the returned\n    /// future is not polled to completion, the behavior of any subsequent calls\n    /// to the SendStream are undefined and data may be lost.\n    async fn send<'a>(\n        &mut self,\n        item: ServerResponseStreamItem<'a>,\n        options: SendOptions,\n    ) -> Result<(), ()>;\n}\n\n#[async_trait]\ntrait DynSendStream: Send {\n    async fn dyn_send<'a>(\n        &mut self,\n        item: ServerResponseStreamItem<'a>,\n        options: SendOptions,\n    ) -> Result<(), ()>;\n}\n\n#[async_trait]\nimpl<T: SendStream> DynSendStream for T {\n    async fn dyn_send<'a>(\n        &mut self,\n        item: ServerResponseStreamItem<'a>,\n        options: SendOptions,\n    ) -> Result<(), ()> {\n        self.send(item, options).await\n    }\n}\n\nimpl SendStream for &mut dyn DynSendStream {\n    async fn send<'a>(\n        &mut self,\n        item: ServerResponseStreamItem<'a>,\n        options: SendOptions,\n    ) -> Result<(), ()> {\n        (**self).dyn_send(item, options).await\n    }\n}\n\nimpl SendStream for Box<dyn DynSendStream> {\n    async fn send<'a>(\n        &mut self,\n        item: ServerResponseStreamItem<'a>,\n        options: SendOptions,\n    ) -> Result<(), ()> {\n        (**self).dyn_send(item, options).await\n    }\n}\n\n/// Contains settings to configure a send operation on a SendStream.\n#[derive(Default)]\n#[non_exhaustive]\npub struct SendOptions {\n    /// Delays sending the message until the trailers are provided on the stream\n    /// and batches the two items together if possible.\n    pub final_msg: bool,\n    /// If set, compression will be disabled for this message.\n    pub disable_compression: bool,\n}\n\n/// Represents the receiving side of a server stream.\n#[trait_variant::make(Send)]\npub trait RecvStream {\n    /// Returns the next message on the stream.  If an error is returned, the\n    /// stream ended or the client closed the send side of the request stream.\n    ///\n    /// # Cancel safety\n    ///\n    /// This method is not intended to be cancellation safe.  If the returned\n    /// future is not polled to completion, the behavior of any subsequent calls\n    /// to the RecvStream are undefined and data may be lost.\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> Result<(), ()>;\n}\n\n#[async_trait]\ntrait DynRecvStream: Send {\n    async fn dyn_next(&mut self, msg: &mut dyn RecvMessage) -> Result<(), ()>;\n}\n\n#[async_trait]\nimpl<T: RecvStream> DynRecvStream for T {\n    async fn dyn_next(&mut self, msg: &mut dyn RecvMessage) -> Result<(), ()> {\n        self.next(msg).await\n    }\n}\n\nimpl RecvStream for Box<dyn DynRecvStream> {\n    async fn next(&mut self, msg: &mut dyn RecvMessage) -> Result<(), ()> {\n        (**self).dyn_next(msg).await\n    }\n}\n"
  },
  {
    "path": "grpc/src/status/server_status.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse crate::status::Status;\nuse crate::status::status_code::StatusCode;\n\n/// Represents a gRPC status on the server.\n///\n/// This is a separate type from `Status` to prevent accidental conversion and\n/// leaking of sensitive information from the server to the client.\n#[derive(Debug, Clone)]\npub struct ServerStatus(Status);\n\nimpl std::ops::Deref for ServerStatus {\n    type Target = Status;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl ServerStatus {\n    /// Create a new `ServerStatus` with the given code and message.\n    pub fn new(code: StatusCode, message: impl Into<String>) -> Self {\n        ServerStatus(Status::new(code, message))\n    }\n\n    /// Create a new `ServerStatus` from a `Status`.\n    pub fn from_status(status: Status) -> Self {\n        ServerStatus(status)\n    }\n\n    /// Converts the `ServerStatus` to a `Status` for client responses.\n    pub(crate) fn into_status(self) -> Status {\n        self.0\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_server_status_new() {\n        let status = ServerStatus::new(StatusCode::Ok, \"ok\");\n        assert_eq!(status.code(), StatusCode::Ok);\n        assert_eq!(status.message(), \"ok\");\n    }\n\n    #[test]\n    fn test_server_status_deref() {\n        let status = ServerStatus::new(StatusCode::Ok, \"ok\");\n        assert_eq!(status.code(), StatusCode::Ok);\n    }\n\n    #[test]\n    fn test_server_status_from_status() {\n        let status = Status::new(StatusCode::Ok, \"ok\");\n        let server_status = ServerStatus::from_status(status);\n        assert_eq!(server_status.code(), StatusCode::Ok);\n    }\n\n    #[test]\n    fn test_server_status_into_status() {\n        let server_status = ServerStatus::new(StatusCode::Ok, \"ok\");\n        let status = server_status.into_status();\n        assert_eq!(status.code(), StatusCode::Ok);\n    }\n}\n"
  },
  {
    "path": "grpc/src/status/status_code.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\n/// Represents a gRPC status code.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\n#[repr(i32)]\npub enum StatusCode {\n    Ok = 0,\n    Cancelled = 1,\n    Unknown = 2,\n    InvalidArgument = 3,\n    DeadlineExceeded = 4,\n    NotFound = 5,\n    AlreadyExists = 6,\n    PermissionDenied = 7,\n    ResourceExhausted = 8,\n    FailedPrecondition = 9,\n    Aborted = 10,\n    OutOfRange = 11,\n    Unimplemented = 12,\n    Internal = 13,\n    Unavailable = 14,\n    DataLoss = 15,\n    Unauthenticated = 16,\n}\n\nimpl From<i32> for StatusCode {\n    fn from(i: i32) -> Self {\n        match i {\n            0 => StatusCode::Ok,\n            1 => StatusCode::Cancelled,\n            2 => StatusCode::Unknown,\n            3 => StatusCode::InvalidArgument,\n            4 => StatusCode::DeadlineExceeded,\n            5 => StatusCode::NotFound,\n            6 => StatusCode::AlreadyExists,\n            7 => StatusCode::PermissionDenied,\n            8 => StatusCode::ResourceExhausted,\n            9 => StatusCode::FailedPrecondition,\n            10 => StatusCode::Aborted,\n            11 => StatusCode::OutOfRange,\n            12 => StatusCode::Unimplemented,\n            13 => StatusCode::Internal,\n            14 => StatusCode::Unavailable,\n            15 => StatusCode::DataLoss,\n            16 => StatusCode::Unauthenticated,\n            _ => StatusCode::Unknown,\n        }\n    }\n}\n"
  },
  {
    "path": "grpc/src/status.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nmod server_status;\nmod status_code;\n\npub use server_status::ServerStatus;\npub use status_code::StatusCode;\n\n/// Represents a gRPC status.\n#[derive(Debug, Clone)]\npub struct Status {\n    code: StatusCode,\n    message: String,\n}\n\nimpl Status {\n    /// Create a new `Status` with the given code and message.\n    pub fn new(code: StatusCode, message: impl Into<String>) -> Self {\n        Status {\n            code,\n            message: message.into(),\n        }\n    }\n\n    /// Get the `StatusCode` of this `Status`.\n    pub fn code(&self) -> StatusCode {\n        self.code\n    }\n\n    /// Get the message of this `Status`.\n    pub fn message(&self) -> &str {\n        &self.message\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_status_new() {\n        let status = Status::new(StatusCode::Ok, \"ok\");\n        assert_eq!(status.code(), StatusCode::Ok);\n        assert_eq!(status.message(), \"ok\");\n    }\n\n    #[test]\n    fn test_status_debug() {\n        let status = Status::new(StatusCode::Ok, \"ok\");\n        let debug = format!(\"{:?}\", status);\n        assert!(debug.contains(\"Status\"));\n        assert!(debug.contains(\"Ok\"));\n        assert!(debug.contains(\"ok\"));\n    }\n}\n"
  },
  {
    "path": "interop/Cargo.toml",
    "content": "[package]\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2024\"\nlicense = \"MIT\"\nname = \"interop\"\nrust-version = { workspace = true }\n\n[[bin]]\nname = \"client\"\npath = \"src/bin/client.rs\"\n\n[[bin]]\nname = \"server\"\npath = \"src/bin/server.rs\"\n\n[dependencies]\nasync-stream = \"0.3\"\nstrum = {version = \"0.27\", features = [\"derive\"]}\npico-args = {version = \"0.5\", features = [\"eq-separator\"]}\nconsole = \"0.16\"\nhttp = \"1\"\nhttp-body-util = \"0.1\"\nprost = \"0.14\"\ntokio = {version = \"1.0\", features = [\"rt-multi-thread\", \"time\", \"macros\"]}\ntokio-stream = \"0.1\"\ntonic = {path = \"../tonic\", features = [\"tls-ring\"]}\ntonic-prost = {path = \"../tonic-prost\"}\ntower = \"0.5\"\ntracing-subscriber = {version = \"0.3\"}\ngrpc = {path = \"../grpc\"}\n# TODO: Remove once the protobuf-codegen crate supports configuring the path to\n# the protobuf crate used in the generated message code, instead of defaulting\n# to `::protobuf`.\nprotobuf = { version = \"4.33.0-release\" }\ntonic-protobuf = {path = \"../tonic-protobuf\"}\n\n[build-dependencies]\ntonic-prost-build = {path = \"../tonic-prost-build\"}\ntonic-protobuf-build = {path = \"../tonic-protobuf-build\"}\n"
  },
  {
    "path": "interop/build.rs",
    "content": "fn main() {\n    let proto = \"proto/grpc/testing/test.proto\";\n\n    eprintln!(\"{}\", tonic_protobuf_build::protoc());\n    let path = std::env::var(\"PATH\").unwrap_or_default();\n    unsafe {\n        std::env::set_var(\"PATH\", format!(\"{}:{}\", path, tonic_protobuf_build::bin()));\n    }\n\n    tonic_prost_build::compile_protos(proto).unwrap();\n    tonic_protobuf_build::CodeGen::new()\n        .include(\"proto/grpc/testing\")\n        .inputs([\"test.proto\", \"empty.proto\", \"messages.proto\"])\n        .compile()\n        .unwrap();\n\n    // prevent needing to rebuild if files (or deps) haven't changed\n    println!(\"cargo:rerun-if-changed={proto}\");\n}\n"
  },
  {
    "path": "interop/data/README.md",
    "content": "# Tonic Testing Certificates\n\nThis directory contains certificates used for testing interop between Tonic's\nimplementation of gRPC and the Go implementation. Certificates are generated\nusing [`terraform`][tf].\n\nTo regenerate certificates for some reason, do the following:\n\n1. Install Terraform 0.12 (or higher)\n1. From the `cert-generator` directory, run:\n    1. `terraform init`\n    1. `terraform apply`\n\nThis will generate certificates and write them to the filesystem. The effective\nversion should be committed to git.\n\n[tf]: https://terraform.io\n"
  },
  {
    "path": "interop/data/ca.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDRjCCAi6gAwIBAgIQd5pnuFdwgGxb4RiClYEPMTANBgkqhkiG9w0BAQsFADA9\nMQ4wDAYDVQQKEwVUb2tpbzEQMA4GA1UECxMHVGVzdGluZzEZMBcGA1UEAxMQVG9u\naWMgVGVzdGluZyBDQTAeFw0yNTA1MDExNzQyNThaFw0zNTA0MjkxNzQyNThaMD0x\nDjAMBgNVBAoTBVRva2lvMRAwDgYDVQQLEwdUZXN0aW5nMRkwFwYDVQQDExBUb25p\nYyBUZXN0aW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2C37\nLVCs4RfNdwv8NMZfIdFNqrUdwzXZ+a5B7Pee1nOL+JD9feOGn1qGZI1ZgFMqVygN\nejSkzlbouN9RAGgyBmOFFo3oEc+nz7kPrezBLoM3oVgNzhEixz2IQoafoZX3j48Y\nfpGYmrTHUp4MAwUAt6Zb+kD7YGqD8//I5OMM4Y5R8yuYGsJHUUSZqYfgXCk0ZvVG\nEX7zyr31cVLqto1vpuv5Uvp6WX5oGgbZVB0wvlqs9Ak+dblWBZQIsrUPU8kn/6kx\nHilF8Lw24dRXr5oveFDMdD/n4sIh7Gr/O+VGH83gP/PawXy0WWn5qGAhdx+P99jI\nUGAWNetu4vGgASLFkwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/\nBAUwAwEB/zAdBgNVHQ4EFgQU4AI0rUoGKFxe0gXIYujrhnuNsocwDQYJKoZIhvcN\nAQELBQADggEBAEtSrTgz+suVMDRsdvxG7+BAcXfVc8pmou3KIFbDtIyog2BEU5nU\nZ+zBqrVgbGv9B4D7XLcZgTShY17cvJP8QpUwT/gzI9uR8Lig9JGF7n1K43+aiAk9\ns7H8e74rwyPX6mRmuznd1sJdDsc5lohUPpZVI+7pRywedQw+QG6/n2cVvR0k0Txh\npF1XBpzuFA5t5uqW/v/QFqfGEuIDDMdW2JQSEB7UyH4V2yWswoYb/uf/xoNXWWqs\nY6RVSp6qVW8748rPPwmLaN8hHGIUNUnilQIXr67bX8i3FjoLHhQvKqUEKciXJWj9\nssGOvq0QoVZNPltcZp9yID3W2kyxv6Hq8VA=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "interop/data/cert-generator/.gitignore",
    "content": ".terraform/\n*.tfstate\n*.tfstate.backup\n"
  },
  {
    "path": "interop/data/cert-generator/ca.tf",
    "content": "resource \"tls_private_key\" \"root\" {\n  algorithm = \"RSA\"\n  rsa_bits = \"2048\"\n}\n\nresource \"tls_self_signed_cert\" \"root\" {\n  private_key_pem = tls_private_key.root.private_key_pem\n\n  validity_period_hours = 87600\n  early_renewal_hours = 8760\n\n  is_ca_certificate = true\n\n  allowed_uses = [\"cert_signing\"]\n\n  subject {\n    common_name = \"Tonic Testing CA\"\n    organization = \"Tokio\"\n    organizational_unit = \"Testing\"\n  }\n}\n\nresource \"local_file\" \"ca_cert\" {\n  filename = \"../ca.pem\"\n  content = tls_self_signed_cert.root.cert_pem\n}\n"
  },
  {
    "path": "interop/data/cert-generator/server_certs.tf",
    "content": "resource \"tls_private_key\" \"server\" {\n  algorithm = \"RSA\"\n  rsa_bits = \"2048\"\n}\n\nresource \"tls_cert_request\" \"server\" {\n  private_key_pem = tls_private_key.server.private_key_pem\n\n  subject {\n    common_name = \"Tonic Test Server Cert\"\n  }\n\n  dns_names = [\n    \"*.test.google.fr\",\n  ]\n}\n\nresource \"tls_locally_signed_cert\" \"server\" {\n  cert_request_pem = tls_cert_request.server.cert_request_pem\n\n  ca_private_key_pem = tls_private_key.root.private_key_pem\n  ca_cert_pem = tls_self_signed_cert.root.cert_pem\n\n  validity_period_hours = 43800\n  early_renewal_hours = 8760\n\n  allowed_uses = [\"server_auth\"]\n}\n\nresource \"local_file\" \"server_cert\" {\n  filename = \"../server1.pem\"\n  content = tls_locally_signed_cert.server.cert_pem\n}\n\nresource \"local_file\" \"server_key\" {\n  filename = \"../server1.key\"\n  content = tls_private_key.server.private_key_pem\n}\n"
  },
  {
    "path": "interop/data/server1.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA7iJJ8gLlKsp+r15CR15Iz2rmi3f3OZmA8FZ0hpB5hNkQHfVA\nRlC2yawIfHiLO4tpUmjtX8iq3RXPkKPYP5Zfd1BDLdR/2qhd3vFJnRVfoiqTMNOV\n3R3+tIm04gDbtGxIDuWL+No/r/KldFxwbLqYTXDOaa145YI2aZ3GZ3P6GFYls6h7\nPeUqlXv7yWx1jfcMIZPeupHwWESYCCLkpvBHFZftWhc/FChUmgr417vmQC2eGwuX\nLyRdu+Lv9NmSzsO6A+w8ss62ewC02LXkXAG2Prd1GYuScsq94GcE5lguC5TVkdTm\ntQMDmET/KvitG3vLB9AIkKnjZdi1Ml7Ow6dByQIDAQABAoIBAFo7ketrH2z8d855\nmAG0/z/hEOSuG3au7MWk7NiEbBdjrJC9epJqSSjX0AtiHdf9NnZsne2aeuv1NMZo\n3ysRDrGGLz5xc9Tl0VQF98/W5nrrSQTKV9IGaJn+SBUPIDEYiqFiZ4xvHozME9eo\no0z/03Acm4o9mj7U/Us95o0SzCRl3QKgAWeSS36Ks0OmDJfNuYBWf+WA7Fte9NUp\nyOOm2fGejoge9eMcJY3/7HckrESscMECZMUL1hBbVD939d4S4AvM6YWTErAa9uq9\nAPsXdu5IYglonqw6oc4TtN9bI9gbHKTyiFgi42gM6qcN2ixpQ78ufktLcJLBTLzi\njP5f5cUCgYEA7whtTRG+KN3nAaRy5gU3JDdOIM1tlAVjwtvUIre3sf6p6Bzs0+RL\nDVdOidJB+8wnV6hF64+juHS27Y7t4ONt2VRFNmY3yRlb9MwqOYlqGaOOewgY+Gab\nZC4GBKmMRKW0LpeRHghpCeyeRRKr5tkYalyU9/C+mxIFpb0/NZZXh6sCgYEA/wmG\ns+npJH2Xs17Yd3wwroZpFAlG2wRCd0IS14brKr+w5czbGis8Pz/LCVrNH+6ZkvoI\ngUpTDwY7egt9O2iCIeSeq82Ov+g9WiDa150YTq8av09N7AZ13Na+SU5aNpPwIOEZ\nWX8dygNloSh4JDjOhrwigRtcMmYCtpKVS792GFsCgYEA6QEB6rp870E/ya4QAoDa\n+4adtgQJ6NxIHs5Cv4Tun6dq4EQx52sGbf7JJDe88kJTp3L0lWbzZP8AwhktcKbB\nkbQ/s4N4paL+rGXIU0XMEyoH3Y5LKPh8SO9EFo9fmBsexLwiTXBNU8s/jH1i7Ch7\nUFLnM7mNU4QB1Ungr8/ZivkCgYA6sA2ATz5oOEJ1c0jqzfhB4QpDIxNcCPHmkZzW\nXeS11KC3cNmmfvaBM4PcZjm3tGdArCrS3bCZT3zWS9iImDcB56Mfs9C6lo2vtMnH\nPg4+5QqJpY0v2Bi9NelZ4x7dWlOyrTnxH1BSkU+Ms0xaQXw9AwQJo6smqdTMAJU8\ndhWN6wKBgQDRAjpfV77FE32XsBkHyGlaIanxu+gSJVLaHStZLV8qTvn//lnmr5Be\nabK4smlwHp5ZnTwqP3gMh/b8vfyPYHdK/2rCKSCEPf/JHtoABsw9Hvkr/N99MZQd\nS2l3PYQoQ8smUVYNWhdYvdRER8WFTk5rPX6fEoVne/sArxlwk8+8nw==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "interop/data/server1.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIRAL1ZcIwdi/AfgLm2T41fHO4wDQYJKoZIhvcNAQELBQAw\nPTEOMAwGA1UEChMFVG9raW8xEDAOBgNVBAsTB1Rlc3RpbmcxGTAXBgNVBAMTEFRv\nbmljIFRlc3RpbmcgQ0EwHhcNMjUwNTAxMTc0MjU4WhcNMzAwNDMwMTc0MjU4WjAh\nMR8wHQYDVQQDExZUb25pYyBUZXN0IFNlcnZlciBDZXJ0MIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEA7iJJ8gLlKsp+r15CR15Iz2rmi3f3OZmA8FZ0hpB5\nhNkQHfVARlC2yawIfHiLO4tpUmjtX8iq3RXPkKPYP5Zfd1BDLdR/2qhd3vFJnRVf\noiqTMNOV3R3+tIm04gDbtGxIDuWL+No/r/KldFxwbLqYTXDOaa145YI2aZ3GZ3P6\nGFYls6h7PeUqlXv7yWx1jfcMIZPeupHwWESYCCLkpvBHFZftWhc/FChUmgr417vm\nQC2eGwuXLyRdu+Lv9NmSzsO6A+w8ss62ewC02LXkXAG2Prd1GYuScsq94GcE5lgu\nC5TVkdTmtQMDmET/KvitG3vLB9AIkKnjZdi1Ml7Ow6dByQIDAQABo2MwYTATBgNV\nHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFOACNK1K\nBihcXtIFyGLo64Z7jbKHMBsGA1UdEQQUMBKCECoudGVzdC5nb29nbGUuZnIwDQYJ\nKoZIhvcNAQELBQADggEBAJP9h4voqemt8Jiw9lgXKOfZyydIHKvL8oeeNQLnn+Ch\nS8D32xRxDeql0oghbTFj1AUxs5X415YgyP4JBoQ8X+L7z3hvSHHildJjbDAM5l+D\njHIr/G6+N6DzLi75WUpZkHFa0ZZ+jHkrxRFq3SsS2hzL93sZ8HoLoEXgGJYcuVYh\nduWmy1pv/TW8j3GcRE358rLyIzsAK2tJZOHC3MeDqvITfGfzeHxy/UG2bbGmXU8Z\nUoCFUGHhukNuESQFfPxoHsWnsxvCIvcIxGPj4NXSO0WJ9r7/A+UczSr+Vuc55h0E\nqrAl9EXltUWTjRZwdIvvas9N3y0ApxkMFNIRmMwUBGE=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "interop/proto/grpc/testing/empty.proto",
    "content": "// Copyright 2015 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage grpc.testing;\n\n// An empty message that you can re-use to avoid defining duplicated empty\n// messages in your project. A typical example is to use it as argument or the\n// return value of a service API. For instance:\n//\n//   service Foo {\n//     rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };\n//   };\n//\nmessage Empty {}\n"
  },
  {
    "path": "interop/proto/grpc/testing/messages.proto",
    "content": "// Copyright 2015-2016 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Message definitions to be used by integration test service definitions.\n\nsyntax = \"proto3\";\n\npackage grpc.testing;\n\n// TODO(dgq): Go back to using well-known types once\n// https://github.com/grpc/grpc/issues/6980 has been fixed.\n// import \"google/protobuf/wrappers.proto\";\nmessage BoolValue {\n  // The bool value.\n  bool value = 1;\n}\n\n// DEPRECATED, don't use. To be removed shortly.\n// The type of payload that should be returned.\nenum PayloadType {\n  // Compressable text format.\n  COMPRESSABLE = 0;\n}\n\n// A block of data, to simply increase gRPC message size.\nmessage Payload {\n  // DEPRECATED, don't use. To be removed shortly.\n  // The type of data in body.\n  PayloadType type = 1;\n  // Primary contents of payload.\n  bytes body = 2;\n}\n\n// A protobuf representation for grpc status. This is used by test\n// clients to specify a status that the server should attempt to return.\nmessage EchoStatus {\n  int32 code = 1;\n  string message = 2;\n}\n\n// Unary request.\nmessage SimpleRequest {\n  // DEPRECATED, don't use. To be removed shortly.\n  // Desired payload type in the response from the server.\n  // If response_type is RANDOM, server randomly chooses one from other formats.\n  PayloadType response_type = 1;\n\n  // Desired payload size in the response from the server.\n  int32 response_size = 2;\n\n  // Optional input payload sent along with the request.\n  Payload payload = 3;\n\n  // Whether SimpleResponse should include username.\n  bool fill_username = 4;\n\n  // Whether SimpleResponse should include OAuth scope.\n  bool fill_oauth_scope = 5;\n\n  // Whether to request the server to compress the response. This field is\n  // \"nullable\" in order to interoperate seamlessly with clients not able to\n  // implement the full compression tests by introspecting the call to verify\n  // the response's compression status.\n  BoolValue response_compressed = 6;\n\n  // Whether server should return a given status\n  EchoStatus response_status = 7;\n\n  // Whether the server should expect this request to be compressed.\n  BoolValue expect_compressed = 8;\n}\n\n// Unary response, as configured by the request.\nmessage SimpleResponse {\n  // Payload to increase message size.\n  Payload payload = 1;\n  // The user the request came from, for verifying authentication was\n  // successful when the client expected it.\n  string username = 2;\n  // OAuth scope.\n  string oauth_scope = 3;\n}\n\n// Client-streaming request.\nmessage StreamingInputCallRequest {\n  // Optional input payload sent along with the request.\n  Payload payload = 1;\n\n  // Whether the server should expect this request to be compressed. This field\n  // is \"nullable\" in order to interoperate seamlessly with servers not able to\n  // implement the full compression tests by introspecting the call to verify\n  // the request's compression status.\n  BoolValue expect_compressed = 2;\n\n  // Not expecting any payload from the response.\n}\n\n// Client-streaming response.\nmessage StreamingInputCallResponse {\n  // Aggregated size of payloads received from the client.\n  int32 aggregated_payload_size = 1;\n}\n\n// Configuration for a particular response.\nmessage ResponseParameters {\n  // Desired payload sizes in responses from the server.\n  int32 size = 1;\n\n  // Desired interval between consecutive responses in the response stream in\n  // microseconds.\n  int32 interval_us = 2;\n\n  // Whether to request the server to compress the response. This field is\n  // \"nullable\" in order to interoperate seamlessly with clients not able to\n  // implement the full compression tests by introspecting the call to verify\n  // the response's compression status.\n  BoolValue compressed = 3;\n}\n\n// Server-streaming request.\nmessage StreamingOutputCallRequest {\n  // DEPRECATED, don't use. To be removed shortly.\n  // Desired payload type in the response from the server.\n  // If response_type is RANDOM, the payload from each response in the stream\n  // might be of different types. This is to simulate a mixed type of payload\n  // stream.\n  PayloadType response_type = 1;\n\n  // Configuration for each expected response message.\n  repeated ResponseParameters response_parameters = 2;\n\n  // Optional input payload sent along with the request.\n  Payload payload = 3;\n\n  // Whether server should return a given status\n  EchoStatus response_status = 7;\n}\n\n// Server-streaming response, as configured by the request and parameters.\nmessage StreamingOutputCallResponse {\n  // Payload to increase response size.\n  Payload payload = 1;\n}\n\n// For reconnect interop test only.\n// Client tells server what reconnection parameters it used.\nmessage ReconnectParams {\n  int32 max_reconnect_backoff_ms = 1;\n}\n\n// For reconnect interop test only.\n// Server tells client whether its reconnects are following the spec and the\n// reconnect backoffs it saw.\nmessage ReconnectInfo {\n  bool passed = 1;\n  repeated int32 backoff_ms = 2;\n}\n"
  },
  {
    "path": "interop/proto/grpc/testing/test.proto",
    "content": "// Copyright 2015-2016 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// An integration test service that covers all the method signature permutations\n// of unary/streaming requests/responses.\n\nsyntax = \"proto3\";\n\nimport \"empty.proto\";\nimport \"messages.proto\";\n\npackage grpc.testing;\n\n// A simple service to test the various types of RPCs and experiment with\n// performance with various types of payload.\nservice TestService {\n  // One empty request followed by one empty response.\n  rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);\n\n  // One request followed by one response.\n  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);\n\n  // One request followed by one response. Response has cache control\n  // headers set such that a caching HTTP proxy (such as GFE) can\n  // satisfy subsequent requests.\n  rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse);\n\n  // One request followed by a sequence of responses (streamed download).\n  // The server returns the payload with client desired type and sizes.\n  rpc StreamingOutputCall(StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // A sequence of requests followed by one response (streamed upload).\n  // The server returns the aggregated size of client payload as the result.\n  rpc StreamingInputCall(stream StreamingInputCallRequest)\n      returns (StreamingInputCallResponse);\n\n  // A sequence of requests with each request served by the server immediately.\n  // As one request could lead to multiple responses, this interface\n  // demonstrates the idea of full duplexing.\n  rpc FullDuplexCall(stream StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // A sequence of requests followed by a sequence of responses.\n  // The server buffers all the client requests and then serves them in order. A\n  // stream of responses are returned to the client when the server starts with\n  // first request.\n  rpc HalfDuplexCall(stream StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // The test server will not implement this method. It will be used\n  // to test the behavior when clients call unimplemented methods.\n  rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);\n}\n\n// A simple service NOT implemented at servers so clients can test for\n// that case.\nservice UnimplementedService {\n  // A call that no server should implement\n  rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);\n}\n\n// A service used to control reconnect server.\nservice ReconnectService {\n  rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty);\n  rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo);\n}\n"
  },
  {
    "path": "interop/src/bin/client.rs",
    "content": "use interop::client::{InteropTest, InteropTestUnimplemented};\nuse interop::{client_prost, client_protobuf};\nuse std::{str::FromStr, time::Duration};\nuse tonic::transport::Endpoint;\nuse tonic::transport::{Certificate, ClientTlsConfig};\n\n#[derive(Debug)]\nstruct Opts {\n    use_tls: bool,\n    test_case: Vec<Testcase>,\n    codec: Codec,\n}\n\n#[derive(Debug)]\nenum Codec {\n    Prost,\n    Protobuf,\n}\n\nimpl FromStr for Codec {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"prost\" => Ok(Codec::Prost),\n            \"protobuf\" => Ok(Codec::Protobuf),\n            _ => Err(format!(\"Invalid codec: {}\", s)),\n        }\n    }\n}\n\nimpl Opts {\n    fn parse() -> Result<Self, pico_args::Error> {\n        let mut pargs = pico_args::Arguments::from_env();\n        Ok(Self {\n            use_tls: pargs.contains(\"--use_tls\"),\n            test_case: pargs.value_from_fn(\"--test_case\", |test_case| {\n                test_case.split(',').map(Testcase::from_str).collect()\n            })?,\n            codec: pargs.value_from_str(\"--codec\")?,\n        })\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    interop::trace_init();\n\n    let matches = Opts::parse()?;\n\n    let test_cases = matches.test_case;\n\n    let scheme = if matches.use_tls { \"https\" } else { \"http\" };\n\n    #[allow(unused_mut)]\n    let mut endpoint = Endpoint::try_from(format!(\"{scheme}://localhost:10000\"))?\n        .timeout(Duration::from_secs(5))\n        .concurrency_limit(30);\n\n    if matches.use_tls {\n        let pem = std::fs::read_to_string(\"interop/data/ca.pem\")?;\n        let ca = Certificate::from_pem(pem);\n        endpoint = endpoint.tls_config(\n            ClientTlsConfig::new()\n                .ca_certificate(ca)\n                .domain_name(\"foo.test.google.fr\"),\n        )?;\n    }\n\n    let channel = endpoint.connect().await?;\n\n    let (mut client, mut unimplemented_client): (\n        Box<dyn InteropTest>,\n        Box<dyn InteropTestUnimplemented>,\n    ) = match matches.codec {\n        Codec::Prost => (\n            Box::new(client_prost::TestClient::new(channel.clone())),\n            Box::new(client_prost::UnimplementedClient::new(channel)),\n        ),\n        Codec::Protobuf => (\n            Box::new(client_protobuf::TestClient::new(channel.clone())),\n            Box::new(client_protobuf::UnimplementedClient::new(channel)),\n        ),\n    };\n\n    let mut failures = Vec::new();\n\n    for test_case in test_cases {\n        println!(\"{test_case:?}:\");\n        let mut test_results = Vec::new();\n\n        match test_case {\n            Testcase::EmptyUnary => client.empty_unary(&mut test_results).await,\n            Testcase::LargeUnary => client.large_unary(&mut test_results).await,\n            Testcase::ClientStreaming => client.client_streaming(&mut test_results).await,\n            Testcase::ServerStreaming => client.server_streaming(&mut test_results).await,\n            Testcase::PingPong => client.ping_pong(&mut test_results).await,\n            Testcase::EmptyStream => client.empty_stream(&mut test_results).await,\n            Testcase::StatusCodeAndMessage => {\n                client.status_code_and_message(&mut test_results).await\n            }\n            Testcase::SpecialStatusMessage => {\n                client.special_status_message(&mut test_results).await\n            }\n            Testcase::UnimplementedMethod => client.unimplemented_method(&mut test_results).await,\n            Testcase::UnimplementedService => {\n                unimplemented_client\n                    .unimplemented_service(&mut test_results)\n                    .await\n            }\n            Testcase::CustomMetadata => client.custom_metadata(&mut test_results).await,\n            _ => unimplemented!(),\n        }\n\n        for result in test_results {\n            println!(\"  {result}\");\n\n            if result.is_failed() {\n                failures.push(result);\n            }\n        }\n    }\n\n    if !failures.is_empty() {\n        println!(\"{} tests failed\", failures.len());\n        std::process::exit(1);\n    }\n\n    Ok(())\n}\n\n#[derive(Debug, strum::EnumString)]\n#[strum(serialize_all = \"snake_case\")]\nenum Testcase {\n    EmptyUnary,\n    CacheableUnary,\n    LargeUnary,\n    ClientCompressedUnary,\n    ServerCompressedUnary,\n    ClientStreaming,\n    ClientCompressedStreaming,\n    ServerStreaming,\n    ServerCompressedStreaming,\n    PingPong,\n    EmptyStream,\n    ComputeEngineCreds,\n    JwtTokenCreds,\n    Oauth2AuthToken,\n    PerRpcCreds,\n    CustomMetadata,\n    StatusCodeAndMessage,\n    SpecialStatusMessage,\n    UnimplementedMethod,\n    UnimplementedService,\n    CancelAfterBegin,\n    CancelAfterFirstResponse,\n    TimeoutOnSleepingServer,\n    ConcurrentLargeUnary,\n}\n"
  },
  {
    "path": "interop/src/bin/server.rs",
    "content": "use interop::{server_prost, server_protobuf};\nuse std::str::FromStr;\nuse tonic::transport::Server;\nuse tonic::transport::{Identity, ServerTlsConfig};\n\n#[derive(Debug)]\nstruct Opts {\n    use_tls: bool,\n    codec: Codec,\n}\n\n#[derive(Debug)]\nenum Codec {\n    Prost,\n    Protobuf,\n}\n\nimpl FromStr for Codec {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"prost\" => Ok(Codec::Prost),\n            \"protobuf\" => Ok(Codec::Protobuf),\n            _ => Err(format!(\"Invalid codec: {}\", s)),\n        }\n    }\n}\n\nimpl Opts {\n    fn parse() -> Result<Self, pico_args::Error> {\n        let mut pargs = pico_args::Arguments::from_env();\n        Ok(Self {\n            use_tls: pargs.contains(\"--use_tls\"),\n            codec: pargs.value_from_str(\"--codec\")?,\n        })\n    }\n}\n\n#[tokio::main]\nasync fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {\n    interop::trace_init();\n\n    let matches = Opts::parse()?;\n\n    let addr = \"127.0.0.1:10000\".parse().unwrap();\n\n    let mut builder = Server::builder();\n\n    if matches.use_tls {\n        let cert = std::fs::read_to_string(\"interop/data/server1.pem\")?;\n        let key = std::fs::read_to_string(\"interop/data/server1.key\")?;\n        let identity = Identity::from_pem(cert, key);\n\n        builder = builder.tls_config(ServerTlsConfig::new().identity(identity))?;\n    }\n\n    match matches.codec {\n        Codec::Prost => {\n            let test_service =\n                server_prost::TestServiceServer::new(server_prost::TestService::default());\n            let unimplemented_service = server_prost::UnimplementedServiceServer::new(\n                server_prost::UnimplementedService::default(),\n            );\n\n            // Wrap this test_service with a service that will echo headers as trailers.\n            let test_service_svc = server_prost::EchoHeadersSvc::new(test_service);\n\n            builder\n                .add_service(test_service_svc)\n                .add_service(unimplemented_service)\n                .serve(addr)\n                .await?;\n        }\n        Codec::Protobuf => {\n            let test_service =\n                server_protobuf::TestServiceServer::new(server_protobuf::TestService::default());\n            let unimplemented_service = server_protobuf::UnimplementedServiceServer::new(\n                server_protobuf::UnimplementedService::default(),\n            );\n\n            // Wrap this test_service with a service that will echo headers as trailers.\n            let test_service_svc = server_protobuf::EchoHeadersSvc::new(test_service);\n\n            builder\n                .add_service(test_service_svc)\n                .add_service(unimplemented_service)\n                .serve(addr)\n                .await?;\n        }\n    };\n\n    Ok(())\n}\n"
  },
  {
    "path": "interop/src/client.rs",
    "content": "use crate::TestAssertion;\nuse tonic::async_trait;\n\n#[async_trait]\npub trait InteropTest: Send {\n    async fn empty_unary(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn large_unary(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn client_streaming(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn server_streaming(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn ping_pong(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn empty_stream(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn status_code_and_message(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn special_status_message(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn unimplemented_method(&mut self, assertions: &mut Vec<TestAssertion>);\n\n    async fn custom_metadata(&mut self, assertions: &mut Vec<TestAssertion>);\n}\n\n#[async_trait]\npub trait InteropTestUnimplemented: Send {\n    async fn unimplemented_service(&mut self, assertions: &mut Vec<TestAssertion>);\n}\n"
  },
  {
    "path": "interop/src/client_prost.rs",
    "content": "use crate::client::{InteropTest, InteropTestUnimplemented};\nuse crate::{\n    TestAssertion, pb::test_service_client::*, pb::unimplemented_service_client::*, pb::*,\n    test_assert,\n};\nuse tokio::sync::mpsc;\nuse tokio_stream::StreamExt;\nuse tonic::async_trait;\nuse tonic::transport::Channel;\nuse tonic::{Code, Request, Response, Status, metadata::MetadataValue};\n\npub type TestClient = TestServiceClient<Channel>;\npub type UnimplementedClient = UnimplementedServiceClient<Channel>;\n\nconst LARGE_REQ_SIZE: usize = 271_828;\nconst LARGE_RSP_SIZE: i32 = 314_159;\nconst REQUEST_LENGTHS: &[i32] = &[27182, 8, 1828, 45904];\nconst RESPONSE_LENGTHS: &[i32] = &[31415, 9, 2653, 58979];\nconst TEST_STATUS_MESSAGE: &str = \"test status message\";\nconst SPECIAL_TEST_STATUS_MESSAGE: &str =\n    \"\\t\\ntest with whitespace\\r\\nand Unicode BMP ☺ and non-BMP 😈\\t\\n\";\n\n#[async_trait]\nimpl InteropTest for TestClient {\n    async fn empty_unary(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let result = self.empty_call(Request::new(Empty {})).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let body = response.into_inner();\n            assertions.push(test_assert!(\n                \"body must not be null\",\n                body == Empty {},\n                format!(\"body={:?}\", body)\n            ));\n        }\n    }\n\n    async fn large_unary(&mut self, assertions: &mut Vec<TestAssertion>) {\n        use std::mem;\n        let payload = crate::client_payload(LARGE_REQ_SIZE);\n        let req = SimpleRequest {\n            response_type: PayloadType::Compressable as i32,\n            response_size: LARGE_RSP_SIZE,\n            payload: Some(payload),\n            ..Default::default()\n        };\n\n        let result = self.unary_call(Request::new(req)).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let body = response.into_inner();\n            let payload_len = body.payload.as_ref().map(|p| p.body.len()).unwrap_or(0);\n\n            assertions.push(test_assert!(\n                \"body must be 314159 bytes\",\n                payload_len == LARGE_RSP_SIZE as usize,\n                format!(\"mem::size_of_val(&body)={:?}\", mem::size_of_val(&body))\n            ));\n        }\n    }\n\n    // async fn cachable_unary(client: &mut Client, assertions: &mut Vec<TestAssertion>) {\n    //     let payload = Payload {\n    //         r#type: PayloadType::Compressable as i32,\n    //         body: format!(\"{:?}\", std::time::Instant::now()).into_bytes(),\n    //     };\n    //     let req = SimpleRequest {\n    //         response_type: PayloadType::Compressable as i32,\n    //         payload: Some(payload),\n    //         ..Default::default()\n    //     };\n\n    //     self.\n    // }\n\n    async fn client_streaming(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let requests: Vec<_> = REQUEST_LENGTHS\n            .iter()\n            .map(make_streaming_input_request)\n            .collect();\n\n        let stream = tokio_stream::iter(requests);\n\n        let result = self.streaming_input_call(Request::new(stream)).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let body = response.into_inner();\n\n            assertions.push(test_assert!(\n                \"aggregated payload size must be 74922 bytes\",\n                body.aggregated_payload_size == 74922,\n                format!(\"aggregated_payload_size={:?}\", body.aggregated_payload_size)\n            ));\n        }\n    }\n\n    async fn server_streaming(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let req = StreamingOutputCallRequest {\n            response_parameters: RESPONSE_LENGTHS\n                .iter()\n                .map(|len| ResponseParameters::with_size(*len))\n                .collect(),\n            ..Default::default()\n        };\n        let req = Request::new(req);\n\n        let result = self.streaming_output_call(req).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let responses = response\n                .into_inner()\n                .filter_map(|m| m.ok())\n                .collect::<Vec<_>>()\n                .await;\n            let actual_response_lengths = crate::response_lengths(&responses);\n            let asserts = vec![\n                test_assert!(\n                    \"there should be four responses\",\n                    responses.len() == 4,\n                    format!(\"responses.len()={:?}\", responses.len())\n                ),\n                test_assert!(\n                    \"the response payload sizes should match input\",\n                    RESPONSE_LENGTHS == actual_response_lengths.as_slice(),\n                    format!(\"{:?}={:?}\", RESPONSE_LENGTHS, actual_response_lengths)\n                ),\n            ];\n\n            assertions.extend(asserts);\n        }\n    }\n\n    async fn ping_pong(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let (tx, rx) = mpsc::unbounded_channel();\n        tx.send(make_ping_pong_request(0)).unwrap();\n\n        let result = self\n            .full_duplex_call(Request::new(\n                tokio_stream::wrappers::UnboundedReceiverStream::new(rx),\n            ))\n            .await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(mut response) = result.map(Response::into_inner) {\n            let mut responses = Vec::new();\n\n            loop {\n                match response.next().await {\n                    Some(result) => {\n                        responses.push(result.unwrap());\n                        if responses.len() == REQUEST_LENGTHS.len() {\n                            drop(tx);\n                            break;\n                        } else {\n                            tx.send(make_ping_pong_request(responses.len())).unwrap();\n                        }\n                    }\n                    None => {\n                        assertions.push(TestAssertion::Failed {\n                            description:\n                                \"server should keep the stream open until the client closes it\",\n                            expression: \"Stream terminated unexpectedly early\",\n                            why: None,\n                        });\n                        break;\n                    }\n                }\n            }\n\n            let actual_response_lengths = crate::response_lengths(&responses);\n            assertions.push(test_assert!(\n                \"there should be four responses\",\n                responses.len() == RESPONSE_LENGTHS.len(),\n                format!(\"{:?}={:?}\", responses.len(), RESPONSE_LENGTHS.len())\n            ));\n            assertions.push(test_assert!(\n                \"the response payload sizes should match input\",\n                RESPONSE_LENGTHS == actual_response_lengths.as_slice(),\n                format!(\"{:?}={:?}\", RESPONSE_LENGTHS, actual_response_lengths)\n            ));\n        }\n    }\n\n    async fn empty_stream(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let stream = tokio_stream::empty();\n        let result = self.full_duplex_call(Request::new(stream)).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result.map(Response::into_inner) {\n            let responses = response.collect::<Vec<_>>().await;\n\n            assertions.push(test_assert!(\n                \"there should be no responses\",\n                responses.is_empty(),\n                format!(\"responses.len()={:?}\", responses.len())\n            ));\n        }\n    }\n\n    async fn status_code_and_message(&mut self, assertions: &mut Vec<TestAssertion>) {\n        fn validate_response<T>(result: Result<T, Status>, assertions: &mut Vec<TestAssertion>)\n        where\n            T: std::fmt::Debug,\n        {\n            assertions.push(test_assert!(\n                \"call must fail with unknown status code\",\n                match &result {\n                    Err(status) => status.code() == Code::Unknown,\n                    _ => false,\n                },\n                format!(\"result={:?}\", result)\n            ));\n\n            assertions.push(test_assert!(\n                \"call must respsond with expected status message\",\n                match &result {\n                    Err(status) => status.message() == TEST_STATUS_MESSAGE,\n                    _ => false,\n                },\n                format!(\"result={:?}\", result)\n            ));\n        }\n\n        let simple_req = SimpleRequest {\n            response_status: Some(EchoStatus {\n                code: 2,\n                message: TEST_STATUS_MESSAGE.to_string(),\n            }),\n            ..Default::default()\n        };\n\n        let duplex_req = StreamingOutputCallRequest {\n            response_status: Some(EchoStatus {\n                code: 2,\n                message: TEST_STATUS_MESSAGE.to_string(),\n            }),\n            ..Default::default()\n        };\n\n        let result = self.unary_call(Request::new(simple_req)).await;\n        validate_response(result, assertions);\n\n        let stream = tokio_stream::once(duplex_req);\n        let result = match self.full_duplex_call(Request::new(stream)).await {\n            Ok(response) => {\n                let stream = response.into_inner();\n                let responses = stream.collect::<Vec<_>>().await;\n                Ok(responses)\n            }\n            Err(e) => Err(e),\n        };\n\n        validate_response(result, assertions);\n    }\n\n    async fn special_status_message(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let req = SimpleRequest {\n            response_status: Some(EchoStatus {\n                code: 2,\n                message: SPECIAL_TEST_STATUS_MESSAGE.to_string(),\n            }),\n            ..Default::default()\n        };\n\n        let result = self.unary_call(Request::new(req)).await;\n\n        assertions.push(test_assert!(\n            \"call must fail with unknown status code\",\n            match &result {\n                Err(status) => status.code() == Code::Unknown,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n\n        assertions.push(test_assert!(\n            \"call must respsond with expected status message\",\n            match &result {\n                Err(status) => status.message() == SPECIAL_TEST_STATUS_MESSAGE,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n    }\n\n    async fn unimplemented_method(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let result = self.unimplemented_call(Request::new(Empty {})).await;\n        assertions.push(test_assert!(\n            \"call must fail with unimplemented status code\",\n            match &result {\n                Err(status) => status.code() == Code::Unimplemented,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n    }\n\n    async fn custom_metadata(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let key1 = \"x-grpc-test-echo-initial\";\n        let value1: MetadataValue<_> = \"test_initial_metadata_value\".parse().unwrap();\n        let key2 = \"x-grpc-test-echo-trailing-bin\";\n        let value2 = MetadataValue::from_bytes(&[0xab, 0xab, 0xab]);\n\n        let req = SimpleRequest {\n            response_type: PayloadType::Compressable as i32,\n            response_size: LARGE_RSP_SIZE,\n            payload: Some(crate::client_payload(LARGE_REQ_SIZE)),\n            ..Default::default()\n        };\n        let mut req_unary = Request::new(req);\n        req_unary.metadata_mut().insert(key1, value1.clone());\n        req_unary.metadata_mut().insert_bin(key2, value2.clone());\n\n        let stream = tokio_stream::once(make_ping_pong_request(0));\n        let mut req_stream = Request::new(stream);\n        req_stream.metadata_mut().insert(key1, value1.clone());\n        req_stream.metadata_mut().insert_bin(key2, value2.clone());\n\n        let response = self.unary_call(req_unary).await.expect(\"call should pass.\");\n\n        assertions.push(test_assert!(\n            \"metadata string must match in unary\",\n            response.metadata().get(key1) == Some(&value1),\n            format!(\"result={:?}\", response.metadata().get(key1))\n        ));\n        assertions.push(test_assert!(\n            \"metadata bin must match in unary\",\n            response.metadata().get_bin(key2) == Some(&value2),\n            format!(\"result={:?}\", response.metadata().get_bin(key1))\n        ));\n\n        let response = self\n            .full_duplex_call(req_stream)\n            .await\n            .expect(\"call should pass.\");\n\n        assertions.push(test_assert!(\n            \"metadata string must match in unary\",\n            response.metadata().get(key1) == Some(&value1),\n            format!(\"result={:?}\", response.metadata().get(key1))\n        ));\n\n        let mut stream = response.into_inner();\n\n        let trailers = stream.trailers().await.unwrap().unwrap();\n\n        assertions.push(test_assert!(\n            \"metadata bin must match in unary\",\n            trailers.get_bin(key2) == Some(&value2),\n            format!(\"result={:?}\", trailers.get_bin(key1))\n        ));\n    }\n}\n\n#[async_trait]\nimpl InteropTestUnimplemented for UnimplementedClient {\n    async fn unimplemented_service(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let result = self.unimplemented_call(Request::new(Empty {})).await;\n        assertions.push(test_assert!(\n            \"call must fail with unimplemented status code\",\n            match &result {\n                Err(status) => status.code() == Code::Unimplemented,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n    }\n}\n\nfn make_ping_pong_request(idx: usize) -> StreamingOutputCallRequest {\n    let req_len = REQUEST_LENGTHS[idx];\n    let resp_len = RESPONSE_LENGTHS[idx];\n    StreamingOutputCallRequest {\n        response_parameters: vec![ResponseParameters::with_size(resp_len)],\n        payload: Some(crate::client_payload(req_len as usize)),\n        ..Default::default()\n    }\n}\n\nfn make_streaming_input_request(len: &i32) -> StreamingInputCallRequest {\n    StreamingInputCallRequest {\n        payload: Some(crate::client_payload(*len as usize)),\n        ..Default::default()\n    }\n}\n"
  },
  {
    "path": "interop/src/client_protobuf.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse crate::client::{InteropTest, InteropTestUnimplemented};\nuse crate::{\n    TestAssertion, grpc_pb::test_service_client::*, grpc_pb::unimplemented_service_client::*,\n    grpc_pb::*, test_assert,\n};\nuse tokio::sync::mpsc;\nuse tokio_stream::StreamExt;\nuse tonic::async_trait;\nuse tonic::transport::Channel;\nuse tonic::{Code, Request, Response, Status, metadata::MetadataValue};\nuse tonic_protobuf::protobuf::__internal::MatcherEq;\nuse tonic_protobuf::protobuf::proto;\n\npub type TestClient = TestServiceClient<Channel>;\npub type UnimplementedClient = UnimplementedServiceClient<Channel>;\n\nconst LARGE_REQ_SIZE: usize = 271_828;\nconst LARGE_RSP_SIZE: i32 = 314_159;\nconst REQUEST_LENGTHS: &[i32] = &[27182, 8, 1828, 45904];\nconst RESPONSE_LENGTHS: &[i32] = &[31415, 9, 2653, 58979];\nconst TEST_STATUS_MESSAGE: &str = \"test status message\";\nconst SPECIAL_TEST_STATUS_MESSAGE: &str =\n    \"\\t\\ntest with whitespace\\r\\nand Unicode BMP ☺ and non-BMP 😈\\t\\n\";\n\n#[async_trait]\nimpl InteropTest for TestClient {\n    async fn empty_unary(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let result = self.empty_call(Request::new(Empty::default())).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let body = response.into_inner();\n            assertions.push(test_assert!(\n                \"body must not be null\",\n                body.matches(&Empty::default()),\n                format!(\"body={:?}\", body)\n            ));\n        }\n    }\n\n    async fn large_unary(&mut self, assertions: &mut Vec<TestAssertion>) {\n        use std::mem;\n        let payload = crate::grpc_utils::client_payload(LARGE_REQ_SIZE);\n        let req = proto!(SimpleRequest {\n            response_type: PayloadType::Compressable,\n            response_size: LARGE_RSP_SIZE,\n            payload: payload,\n        });\n\n        let result = self.unary_call(Request::new(req)).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let body = response.into_inner();\n            let payload_len = body.payload().body().len();\n\n            assertions.push(test_assert!(\n                \"body must be 314159 bytes\",\n                payload_len == LARGE_RSP_SIZE as usize,\n                format!(\"mem::size_of_val(&body)={:?}\", mem::size_of_val(&body))\n            ));\n        }\n    }\n\n    async fn client_streaming(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let requests: Vec<_> = REQUEST_LENGTHS\n            .iter()\n            .map(make_streaming_input_request)\n            .collect();\n\n        let stream = tokio_stream::iter(requests);\n\n        let result = self.streaming_input_call(Request::new(stream)).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let body = response.into_inner();\n\n            assertions.push(test_assert!(\n                \"aggregated payload size must be 74922 bytes\",\n                body.aggregated_payload_size() == 74922,\n                format!(\n                    \"aggregated_payload_size={:?}\",\n                    body.aggregated_payload_size()\n                )\n            ));\n        }\n    }\n\n    async fn server_streaming(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let req = proto!(StreamingOutputCallRequest {\n            response_parameters: RESPONSE_LENGTHS\n                .iter()\n                .map(|len| ResponseParameters::with_size(*len)),\n        });\n        let req = Request::new(req);\n\n        let result = self.streaming_output_call(req).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result {\n            let responses = response\n                .into_inner()\n                .filter_map(|m| m.ok())\n                .collect::<Vec<_>>()\n                .await;\n            let actual_response_lengths = crate::grpc_utils::response_lengths(&responses);\n            let asserts = vec![\n                test_assert!(\n                    \"there should be four responses\",\n                    responses.len() == 4,\n                    format!(\"responses.len()={:?}\", responses.len())\n                ),\n                test_assert!(\n                    \"the response payload sizes should match input\",\n                    RESPONSE_LENGTHS == actual_response_lengths.as_slice(),\n                    format!(\"{:?}={:?}\", RESPONSE_LENGTHS, actual_response_lengths)\n                ),\n            ];\n\n            assertions.extend(asserts);\n        }\n    }\n\n    async fn ping_pong(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let (tx, rx) = mpsc::unbounded_channel();\n        tx.send(make_ping_pong_request(0)).unwrap();\n\n        let result = self\n            .full_duplex_call(Request::new(\n                tokio_stream::wrappers::UnboundedReceiverStream::new(rx),\n            ))\n            .await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(mut response) = result.map(Response::into_inner) {\n            let mut responses = Vec::new();\n\n            loop {\n                match response.next().await {\n                    Some(result) => {\n                        responses.push(result.unwrap());\n                        if responses.len() == REQUEST_LENGTHS.len() {\n                            drop(tx);\n                            break;\n                        } else {\n                            tx.send(make_ping_pong_request(responses.len())).unwrap();\n                        }\n                    }\n                    None => {\n                        assertions.push(TestAssertion::Failed {\n                            description:\n                                \"server should keep the stream open until the client closes it\",\n                            expression: \"Stream terminated unexpectedly early\",\n                            why: None,\n                        });\n                        break;\n                    }\n                }\n            }\n\n            let actual_response_lengths = crate::grpc_utils::response_lengths(&responses);\n            assertions.push(test_assert!(\n                \"there should be four responses\",\n                responses.len() == RESPONSE_LENGTHS.len(),\n                format!(\"{:?}={:?}\", responses.len(), RESPONSE_LENGTHS.len())\n            ));\n            assertions.push(test_assert!(\n                \"the response payload sizes should match input\",\n                RESPONSE_LENGTHS == actual_response_lengths.as_slice(),\n                format!(\"{:?}={:?}\", RESPONSE_LENGTHS, actual_response_lengths)\n            ));\n        }\n    }\n\n    async fn empty_stream(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let stream = tokio_stream::empty();\n        let result = self.full_duplex_call(Request::new(stream)).await;\n\n        assertions.push(test_assert!(\n            \"call must be successful\",\n            result.is_ok(),\n            format!(\"result={:?}\", result)\n        ));\n\n        if let Ok(response) = result.map(Response::into_inner) {\n            let responses = response.collect::<Vec<_>>().await;\n\n            assertions.push(test_assert!(\n                \"there should be no responses\",\n                responses.is_empty(),\n                format!(\"responses.len()={:?}\", responses.len())\n            ));\n        }\n    }\n\n    async fn status_code_and_message(&mut self, assertions: &mut Vec<TestAssertion>) {\n        fn validate_response<T>(result: Result<T, Status>, assertions: &mut Vec<TestAssertion>)\n        where\n            T: std::fmt::Debug,\n        {\n            assertions.push(test_assert!(\n                \"call must fail with unknown status code\",\n                match &result {\n                    Err(status) => status.code() == Code::Unknown,\n                    _ => false,\n                },\n                format!(\"result={:?}\", result)\n            ));\n\n            assertions.push(test_assert!(\n                \"call must respsond with expected status message\",\n                match &result {\n                    Err(status) => status.message() == TEST_STATUS_MESSAGE,\n                    _ => false,\n                },\n                format!(\"result={:?}\", result)\n            ));\n        }\n\n        let simple_req = proto!(SimpleRequest {\n            response_status: EchoStatus {\n                code: 2,\n                message: TEST_STATUS_MESSAGE.to_string(),\n            },\n        });\n\n        let duplex_req = proto!(StreamingOutputCallRequest {\n            response_status: EchoStatus {\n                code: 2,\n                message: TEST_STATUS_MESSAGE.to_string(),\n            },\n        });\n\n        let result = self.unary_call(Request::new(simple_req)).await;\n        validate_response(result, assertions);\n\n        let stream = tokio_stream::once(duplex_req);\n        let result = match self.full_duplex_call(Request::new(stream)).await {\n            Ok(response) => {\n                let stream = response.into_inner();\n                let responses = stream.collect::<Vec<_>>().await;\n                Ok(responses)\n            }\n            Err(e) => Err(e),\n        };\n\n        validate_response(result, assertions);\n    }\n\n    async fn special_status_message(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let req = proto!(SimpleRequest {\n            response_status: EchoStatus {\n                code: 2,\n                message: SPECIAL_TEST_STATUS_MESSAGE.to_string(),\n            },\n        });\n\n        let result = self.unary_call(Request::new(req)).await;\n\n        assertions.push(test_assert!(\n            \"call must fail with unknown status code\",\n            match &result {\n                Err(status) => status.code() == Code::Unknown,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n\n        assertions.push(test_assert!(\n            \"call must respsond with expected status message\",\n            match &result {\n                Err(status) => status.message() == SPECIAL_TEST_STATUS_MESSAGE,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n    }\n\n    async fn unimplemented_method(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let result = self\n            .unimplemented_call(Request::new(Empty::default()))\n            .await;\n        assertions.push(test_assert!(\n            \"call must fail with unimplemented status code\",\n            match &result {\n                Err(status) => status.code() == Code::Unimplemented,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n    }\n\n    async fn custom_metadata(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let key1 = \"x-grpc-test-echo-initial\";\n        let value1: MetadataValue<_> = \"test_initial_metadata_value\".parse().unwrap();\n        let key2 = \"x-grpc-test-echo-trailing-bin\";\n        let value2 = MetadataValue::from_bytes(&[0xab, 0xab, 0xab]);\n\n        let req = proto!(SimpleRequest {\n            response_type: PayloadType::Compressable,\n            response_size: LARGE_RSP_SIZE,\n            payload: crate::grpc_utils::client_payload(LARGE_REQ_SIZE),\n        });\n        let mut req_unary = Request::new(req);\n        req_unary.metadata_mut().insert(key1, value1.clone());\n        req_unary.metadata_mut().insert_bin(key2, value2.clone());\n\n        let stream = tokio_stream::once(make_ping_pong_request(0));\n        let mut req_stream = Request::new(stream);\n        req_stream.metadata_mut().insert(key1, value1.clone());\n        req_stream.metadata_mut().insert_bin(key2, value2.clone());\n\n        let response = self.unary_call(req_unary).await.expect(\"call should pass.\");\n\n        assertions.push(test_assert!(\n            \"metadata string must match in unary\",\n            response.metadata().get(key1) == Some(&value1),\n            format!(\"result={:?}\", response.metadata().get(key1))\n        ));\n        assertions.push(test_assert!(\n            \"metadata bin must match in unary\",\n            response.metadata().get_bin(key2) == Some(&value2),\n            format!(\"result={:?}\", response.metadata().get_bin(key1))\n        ));\n\n        let response = self\n            .full_duplex_call(req_stream)\n            .await\n            .expect(\"call should pass.\");\n\n        assertions.push(test_assert!(\n            \"metadata string must match in unary\",\n            response.metadata().get(key1) == Some(&value1),\n            format!(\"result={:?}\", response.metadata().get(key1))\n        ));\n\n        let mut stream = response.into_inner();\n\n        let trailers = stream.trailers().await.unwrap().unwrap();\n\n        assertions.push(test_assert!(\n            \"metadata bin must match in unary\",\n            trailers.get_bin(key2) == Some(&value2),\n            format!(\"result={:?}\", trailers.get_bin(key1))\n        ));\n    }\n}\n\n#[async_trait]\nimpl InteropTestUnimplemented for UnimplementedClient {\n    async fn unimplemented_service(&mut self, assertions: &mut Vec<TestAssertion>) {\n        let result = self\n            .unimplemented_call(Request::new(Empty::default()))\n            .await;\n        assertions.push(test_assert!(\n            \"call must fail with unimplemented status code\",\n            match &result {\n                Err(status) => status.code() == Code::Unimplemented,\n                _ => false,\n            },\n            format!(\"result={:?}\", result)\n        ));\n    }\n}\n\nfn make_ping_pong_request(idx: usize) -> StreamingOutputCallRequest {\n    let req_len = REQUEST_LENGTHS[idx];\n    let resp_len = RESPONSE_LENGTHS[idx];\n    proto!(StreamingOutputCallRequest {\n        response_parameters: std::iter::once(ResponseParameters::with_size(resp_len)),\n        payload: crate::grpc_utils::client_payload(req_len as usize),\n    })\n}\n\nfn make_streaming_input_request(len: &i32) -> StreamingInputCallRequest {\n    proto!(StreamingInputCallRequest {\n        payload: crate::grpc_utils::client_payload(*len as usize),\n    })\n}\n"
  },
  {
    "path": "interop/src/lib.rs",
    "content": "#![recursion_limit = \"256\"]\n\npub mod client;\npub mod client_prost;\npub mod client_protobuf;\npub mod server_prost;\npub mod server_protobuf;\n\npub mod pb {\n    #![allow(dead_code, unused_imports)]\n    include!(concat!(env!(\"OUT_DIR\"), \"/grpc.testing.rs\"));\n}\n\npub mod grpc_pb {\n    #![allow(\n        dead_code,\n        unused_imports,\n        clippy::clone_on_copy,\n        clippy::useless_conversion,\n        clippy::unnecessary_fallible_conversions,\n        clippy::derivable_impls\n    )]\n    grpc::include_proto!(\"test\");\n}\n\nuse std::{default, fmt, iter};\n\npub fn trace_init() {\n    tracing_subscriber::fmt::init();\n}\n\npub fn client_payload(size: usize) -> pb::Payload {\n    pb::Payload {\n        r#type: default::Default::default(),\n        body: iter::repeat_n(0u8, size).collect(),\n    }\n}\n\npub fn server_payload(size: usize) -> pb::Payload {\n    pb::Payload {\n        r#type: default::Default::default(),\n        body: iter::repeat_n(0u8, size).collect(),\n    }\n}\n\nimpl pb::ResponseParameters {\n    fn with_size(size: i32) -> Self {\n        pb::ResponseParameters {\n            size,\n            ..Default::default()\n        }\n    }\n}\n\nfn response_length(response: &pb::StreamingOutputCallResponse) -> i32 {\n    match &response.payload {\n        Some(payload) => payload.body.len() as i32,\n        None => 0,\n    }\n}\n\nfn response_lengths(responses: &[pb::StreamingOutputCallResponse]) -> Vec<i32> {\n    responses.iter().map(&response_length).collect()\n}\n\nmod grpc_utils {\n    use super::grpc_pb;\n    use protobuf::proto;\n    use std::iter;\n\n    pub(crate) fn client_payload(size: usize) -> grpc_pb::Payload {\n        proto!(grpc_pb::Payload {\n            body: iter::repeat_n(0u8, size).collect::<Vec<_>>(),\n        })\n    }\n\n    impl grpc_pb::ResponseParameters {\n        pub(crate) fn with_size(size: i32) -> Self {\n            proto!(grpc_pb::ResponseParameters { size: size })\n        }\n    }\n\n    pub(crate) fn response_length(response: &grpc_pb::StreamingOutputCallResponse) -> i32 {\n        response.payload().body().len() as i32\n    }\n\n    pub(crate) fn response_lengths(responses: &[grpc_pb::StreamingOutputCallResponse]) -> Vec<i32> {\n        responses.iter().map(&response_length).collect()\n    }\n\n    pub(crate) fn server_payload(size: usize) -> grpc_pb::Payload {\n        proto!(grpc_pb::Payload {\n            body: iter::repeat_n(0u8, size).collect::<Vec<_>>(),\n        })\n    }\n}\n\n#[derive(Debug)]\npub enum TestAssertion {\n    Passed {\n        description: &'static str,\n    },\n    Failed {\n        description: &'static str,\n        expression: &'static str,\n        why: Option<String>,\n    },\n}\n\nimpl TestAssertion {\n    pub fn is_failed(&self) -> bool {\n        matches!(self, TestAssertion::Failed { .. })\n    }\n}\n\nimpl fmt::Display for TestAssertion {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        use console::{Emoji, style};\n        match *self {\n            TestAssertion::Passed { ref description } => write!(\n                f,\n                \"{check} {desc}\",\n                check = style(Emoji(\"✔\", \"+\")).green(),\n                desc = style(description).green(),\n            ),\n            TestAssertion::Failed {\n                ref description,\n                ref expression,\n                why: Some(ref why),\n            } => write!(\n                f,\n                \"{check} {desc}\\n  in `{exp}`: {why}\",\n                check = style(Emoji(\"✖\", \"x\")).red(),\n                desc = style(description).red(),\n                exp = style(expression).red(),\n                why = style(why).red(),\n            ),\n            TestAssertion::Failed {\n                ref description,\n                ref expression,\n                why: None,\n            } => write!(\n                f,\n                \"{check} {desc}\\n  in `{exp}`\",\n                check = style(Emoji(\"✖\", \"x\")).red(),\n                desc = style(description).red(),\n                exp = style(expression).red(),\n            ),\n        }\n    }\n}\n\n#[macro_export]\nmacro_rules! test_assert {\n    ($description:expr, $assertion:expr) => {\n        if $assertion {\n            $crate::TestAssertion::Passed {\n                description: $description,\n            }\n        } else {\n            TestAssertion::Failed {\n                description: $description,\n                expression: stringify!($assertion),\n                why: None,\n            }\n        }\n    };\n    ($description:expr, $assertion:expr, $why:expr) => {\n        if $assertion {\n            $crate::TestAssertion::Passed {\n                description: $description,\n            }\n        } else {\n            $crate::TestAssertion::Failed {\n                description: $description,\n                expression: stringify!($assertion),\n                why: Some($why),\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "interop/src/server_prost.rs",
    "content": "use crate::pb::{self, *};\nuse async_stream::try_stream;\nuse http::header::{HeaderMap, HeaderName};\nuse http_body_util::BodyExt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::result::Result as StdResult;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\nuse tokio_stream::StreamExt;\nuse tonic::{Code, Request, Response, Status, body::Body, server::NamedService};\nuse tower::Service;\n\npub use pb::test_service_server::TestServiceServer;\npub use pb::unimplemented_service_server::UnimplementedServiceServer;\n\n#[derive(Default, Clone)]\npub struct TestService {}\n\ntype Result<T> = StdResult<Response<T>, Status>;\ntype Streaming<T> = Request<tonic::Streaming<T>>;\ntype Stream<T> = Pin<Box<dyn tokio_stream::Stream<Item = StdResult<T, Status>> + Send + 'static>>;\ntype BoxFuture<T, E> = Pin<Box<dyn Future<Output = StdResult<T, E>> + Send + 'static>>;\n\n#[tonic::async_trait]\nimpl pb::test_service_server::TestService for TestService {\n    async fn empty_call(&self, _request: Request<Empty>) -> Result<Empty> {\n        Ok(Response::new(Empty {}))\n    }\n\n    async fn unary_call(&self, request: Request<SimpleRequest>) -> Result<SimpleResponse> {\n        let req = request.into_inner();\n\n        if let Some(echo_status) = req.response_status {\n            let status = Status::new(Code::from_i32(echo_status.code), echo_status.message);\n            return Err(status);\n        }\n\n        let res_size = if req.response_size >= 0 {\n            req.response_size as usize\n        } else {\n            let status = Status::new(Code::InvalidArgument, \"response_size cannot be negative\");\n            return Err(status);\n        };\n\n        let res = SimpleResponse {\n            payload: Some(Payload {\n                body: vec![0; res_size],\n                ..Default::default()\n            }),\n            ..Default::default()\n        };\n\n        Ok(Response::new(res))\n    }\n\n    async fn cacheable_unary_call(&self, _: Request<SimpleRequest>) -> Result<SimpleResponse> {\n        unimplemented!()\n    }\n\n    type StreamingOutputCallStream = Stream<StreamingOutputCallResponse>;\n\n    async fn streaming_output_call(\n        &self,\n        req: Request<StreamingOutputCallRequest>,\n    ) -> Result<Self::StreamingOutputCallStream> {\n        let StreamingOutputCallRequest {\n            response_parameters,\n            ..\n        } = req.into_inner();\n\n        let stream = try_stream! {\n            for param in response_parameters {\n                tokio::time::sleep(Duration::from_micros(param.interval_us as u64)).await;\n\n                let payload = crate::server_payload(param.size as usize);\n                yield StreamingOutputCallResponse { payload: Some(payload) };\n            }\n        };\n\n        Ok(Response::new(\n            Box::pin(stream) as Self::StreamingOutputCallStream\n        ))\n    }\n\n    async fn streaming_input_call(\n        &self,\n        req: Streaming<StreamingInputCallRequest>,\n    ) -> Result<StreamingInputCallResponse> {\n        let mut stream = req.into_inner();\n\n        let mut aggregated_payload_size = 0;\n        while let Some(msg) = stream.try_next().await? {\n            aggregated_payload_size += msg.payload.unwrap().body.len() as i32;\n        }\n\n        let res = StreamingInputCallResponse {\n            aggregated_payload_size,\n        };\n\n        Ok(Response::new(res))\n    }\n\n    type FullDuplexCallStream = Stream<StreamingOutputCallResponse>;\n\n    async fn full_duplex_call(\n        &self,\n        req: Streaming<StreamingOutputCallRequest>,\n    ) -> Result<Self::FullDuplexCallStream> {\n        let mut stream = req.into_inner();\n\n        if let Some(first_msg) = stream.message().await? {\n            if let Some(echo_status) = first_msg.response_status {\n                let status = Status::new(Code::from_i32(echo_status.code), echo_status.message);\n                return Err(status);\n            }\n\n            let single_message = tokio_stream::once(Ok(first_msg));\n            let mut stream = single_message.chain(stream);\n\n            let stream = try_stream! {\n                while let Some(msg) = stream.try_next().await? {\n                    if let Some(echo_status) = msg.response_status {\n                        let status = Status::new(Code::from_i32(echo_status.code), echo_status.message);\n                        Err(status)?;\n                    }\n\n                    for param in msg.response_parameters {\n                        tokio::time::sleep(Duration::from_micros(param.interval_us as u64)).await;\n\n                        let payload = crate::server_payload(param.size as usize);\n                        yield StreamingOutputCallResponse { payload: Some(payload) };\n                    }\n                }\n            };\n\n            Ok(Response::new(Box::pin(stream) as Self::FullDuplexCallStream))\n        } else {\n            let stream = tokio_stream::empty();\n            Ok(Response::new(Box::pin(stream) as Self::FullDuplexCallStream))\n        }\n    }\n\n    type HalfDuplexCallStream = Stream<StreamingOutputCallResponse>;\n\n    async fn half_duplex_call(\n        &self,\n        _: Streaming<StreamingOutputCallRequest>,\n    ) -> Result<Self::HalfDuplexCallStream> {\n        Err(Status::unimplemented(\"TODO\"))\n    }\n\n    async fn unimplemented_call(&self, _: Request<Empty>) -> Result<Empty> {\n        Err(Status::unimplemented(\"\"))\n    }\n}\n\n#[derive(Default)]\npub struct UnimplementedService {}\n\n#[tonic::async_trait]\nimpl pb::unimplemented_service_server::UnimplementedService for UnimplementedService {\n    async fn unimplemented_call(&self, _req: Request<Empty>) -> Result<Empty> {\n        Err(Status::unimplemented(\"\"))\n    }\n}\n\n#[derive(Clone, Default)]\npub struct EchoHeadersSvc<S> {\n    inner: S,\n}\n\nimpl<S: NamedService> NamedService for EchoHeadersSvc<S> {\n    const NAME: &'static str = S::NAME;\n}\n\nimpl<S> EchoHeadersSvc<S> {\n    pub fn new(inner: S) -> Self {\n        Self { inner }\n    }\n}\n\nimpl<S> Service<http::Request<Body>> for EchoHeadersSvc<S>\nwhere\n    S: Service<http::Request<Body>, Response = http::Response<Body>> + Send,\n    S::Future: Send + 'static,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = BoxFuture<Self::Response, Self::Error>;\n\n    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<StdResult<(), Self::Error>> {\n        Ok(()).into()\n    }\n\n    fn call(&mut self, req: http::Request<Body>) -> Self::Future {\n        let echo_header = req.headers().get(\"x-grpc-test-echo-initial\").cloned();\n\n        let trailer_name = HeaderName::from_static(\"x-grpc-test-echo-trailing-bin\");\n        let echo_trailer = req\n            .headers()\n            .get(&trailer_name)\n            .cloned()\n            .map(|v| HeaderMap::from_iter(std::iter::once((trailer_name, v))));\n\n        let call = self.inner.call(req);\n\n        Box::pin(async move {\n            let mut res = call.await?;\n\n            if let Some(echo_header) = echo_header {\n                res.headers_mut()\n                    .insert(\"x-grpc-test-echo-initial\", echo_header);\n                Ok(res\n                    .map(|b| b.with_trailers(async move { echo_trailer.map(Ok) }))\n                    .map(Body::new))\n            } else {\n                Ok(res)\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "interop/src/server_protobuf.rs",
    "content": "use crate::grpc_pb::{self, *};\nuse async_stream::try_stream;\nuse http::header::{HeaderMap, HeaderName};\nuse http_body_util::BodyExt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::result::Result as StdResult;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\nuse tokio_stream::StreamExt;\nuse tonic::codegen::BoxStream;\nuse tonic::{Code, Request, Response, Status, body::Body, server::NamedService};\nuse tonic_protobuf::protobuf::proto;\nuse tower::Service;\n\npub use grpc_pb::test_service_server::TestServiceServer;\npub use grpc_pb::unimplemented_service_server::UnimplementedServiceServer;\n\n#[derive(Default, Clone)]\npub struct TestService {}\n\ntype Result<T> = StdResult<Response<T>, Status>;\ntype Streaming<T> = Request<tonic::Streaming<T>>;\ntype BoxFuture<T, E> = Pin<Box<dyn Future<Output = StdResult<T, E>> + Send + 'static>>;\n\n#[tonic::async_trait]\nimpl grpc_pb::test_service_server::TestService for TestService {\n    async fn empty_call(&self, _request: Request<Empty>) -> Result<Empty> {\n        Ok(Response::new(Empty::default()))\n    }\n\n    async fn unary_call(&self, request: Request<SimpleRequest>) -> Result<SimpleResponse> {\n        let req = request.into_inner();\n\n        if req.response_status().code() != 0 {\n            let echo_status = req.response_status();\n            let status = Status::new(\n                Code::from_i32(echo_status.code()),\n                echo_status.message().to_string(),\n            );\n            return Err(status);\n        }\n\n        let res_size = if req.response_size() >= 0 {\n            req.response_size() as usize\n        } else {\n            let status = Status::new(Code::InvalidArgument, \"response_size cannot be negative\");\n            return Err(status);\n        };\n\n        let res = proto!(SimpleResponse {\n            payload: Payload {\n                body: vec![0; res_size],\n            },\n        });\n\n        Ok(Response::new(res))\n    }\n\n    async fn cacheable_unary_call(&self, _: Request<SimpleRequest>) -> Result<SimpleResponse> {\n        unimplemented!()\n    }\n\n    async fn streaming_output_call(\n        &self,\n        req: tonic::Request<StreamingOutputCallRequest>,\n    ) -> std::result::Result<tonic::Response<BoxStream<StreamingOutputCallResponse>>, tonic::Status>\n    {\n        let stream = try_stream! {\n            for param in req.into_inner().response_parameters() {\n                tokio::time::sleep(Duration::from_micros(param.interval_us() as u64)).await;\n\n                let payload = crate::grpc_utils::server_payload(param.size() as usize);\n                yield proto!(StreamingOutputCallResponse { payload: payload });\n            }\n        };\n\n        Ok(Response::new(Box::pin(stream)))\n    }\n\n    async fn streaming_input_call(\n        &self,\n        req: Streaming<StreamingInputCallRequest>,\n    ) -> Result<StreamingInputCallResponse> {\n        let mut stream = req.into_inner();\n\n        let mut aggregated_payload_size = 0;\n        while let Some(msg) = stream.try_next().await? {\n            aggregated_payload_size += msg.payload().body().len() as i32;\n        }\n\n        let res = proto!(StreamingInputCallResponse {\n            aggregated_payload_size: aggregated_payload_size,\n        });\n\n        Ok(Response::new(res))\n    }\n\n    async fn full_duplex_call(\n        &self,\n        req: tonic::Request<tonic::Streaming<StreamingOutputCallRequest>>,\n    ) -> std::result::Result<tonic::Response<BoxStream<StreamingOutputCallResponse>>, tonic::Status>\n    {\n        let mut stream = req.into_inner();\n\n        if let Some(first_msg) = stream.message().await? {\n            if first_msg.response_status().code() != 0 {\n                let echo_status = first_msg.response_status();\n                let status = Status::new(\n                    Code::from_i32(echo_status.code()),\n                    echo_status.message().to_string(),\n                );\n                return Err(status);\n            }\n\n            let single_message = tokio_stream::once(Ok(first_msg));\n            let mut stream = single_message.chain(stream);\n\n            let stream = try_stream! {\n                while let Some(msg) = stream.try_next().await? {\n                    if msg.response_status().code() != 0 {\n                        let echo_status = msg.response_status();\n                        let status = Status::new(Code::from_i32(echo_status.code()), echo_status.message().to_string());\n                        Err(status)?;\n                    }\n\n                    for param in msg.response_parameters() {\n                        tokio::time::sleep(Duration::from_micros(param.interval_us() as u64)).await;\n\n                        let payload = crate::grpc_utils::server_payload(param.size() as usize);\n                        yield proto!(StreamingOutputCallResponse { payload: payload });\n                    }\n                }\n            };\n\n            Ok(Response::new(Box::pin(stream)))\n        } else {\n            let stream = tokio_stream::empty();\n            Ok(Response::new(Box::pin(stream)))\n        }\n    }\n\n    async fn half_duplex_call(\n        &self,\n        _request: tonic::Request<tonic::Streaming<StreamingOutputCallRequest>>,\n    ) -> std::result::Result<tonic::Response<BoxStream<StreamingOutputCallResponse>>, tonic::Status>\n    {\n        Err(Status::unimplemented(\"TODO\"))\n    }\n\n    async fn unimplemented_call(&self, _: Request<Empty>) -> Result<Empty> {\n        Err(Status::unimplemented(\"\"))\n    }\n}\n\n#[derive(Default)]\npub struct UnimplementedService {}\n\n#[tonic::async_trait]\nimpl grpc_pb::unimplemented_service_server::UnimplementedService for UnimplementedService {\n    async fn unimplemented_call(&self, _req: Request<Empty>) -> Result<Empty> {\n        Err(Status::unimplemented(\"\"))\n    }\n}\n\n#[derive(Clone, Default)]\npub struct EchoHeadersSvc<S> {\n    inner: S,\n}\n\nimpl<S: NamedService> NamedService for EchoHeadersSvc<S> {\n    const NAME: &'static str = S::NAME;\n}\n\nimpl<S> EchoHeadersSvc<S> {\n    pub fn new(inner: S) -> Self {\n        Self { inner }\n    }\n}\n\nimpl<S> Service<http::Request<Body>> for EchoHeadersSvc<S>\nwhere\n    S: Service<http::Request<Body>, Response = http::Response<Body>> + Send,\n    S::Future: Send + 'static,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = BoxFuture<Self::Response, Self::Error>;\n\n    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<StdResult<(), Self::Error>> {\n        Ok(()).into()\n    }\n\n    fn call(&mut self, req: http::Request<Body>) -> Self::Future {\n        let echo_header = req.headers().get(\"x-grpc-test-echo-initial\").cloned();\n\n        let trailer_name = HeaderName::from_static(\"x-grpc-test-echo-trailing-bin\");\n        let echo_trailer = req\n            .headers()\n            .get(&trailer_name)\n            .cloned()\n            .map(|v| HeaderMap::from_iter(std::iter::once((trailer_name, v))));\n\n        let call = self.inner.call(req);\n\n        Box::pin(async move {\n            let mut res = call.await?;\n\n            if let Some(echo_header) = echo_header {\n                res.headers_mut()\n                    .insert(\"x-grpc-test-echo-initial\", echo_header);\n                Ok(res\n                    .map(|b| b.with_trailers(async move { echo_trailer.map(Ok) }))\n                    .map(Body::new))\n            } else {\n                Ok(res)\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "interop/test.sh",
    "content": "#!/usr/bin/env bash\n\nset -eu\nset -o pipefail\n\n# the go client does not support passing an argument with multiple test cases\n# so we loop over this array calling the binary each time around\nTEST_CASES=(\n  \"empty_unary\"\n  \"large_unary\"\n  \"client_streaming\"\n  \"server_streaming\"\n  \"ping_pong\"\n  \"empty_stream\"\n  \"status_code_and_message\"\n  \"special_status_message\"\n  \"custom_metadata\"\n  \"unimplemented_method\"\n  \"unimplemented_service\"\n)\n\n# join all test cases in one comma separated string (dropping the first one)\n# so we can call the rust client only once, reducing the noise\nJOINED_TEST_CASES=$(printf \",%s\" \"${TEST_CASES[@]}\")\nJOINED_TEST_CASES=\"${JOINED_TEST_CASES:1}\"\n\nset -x\n\necho \"Running for OS: ${OSTYPE}\"\n\ncase \"$OSTYPE\" in\n  darwin*)  OS=\"darwin\"; EXT=\"\" ;;\n  linux*)   OS=\"linux\"; EXT=\"\" ;;\n  msys*)    OS=\"windows\"; EXT=\".exe\" ;;\n  *)        exit 2 ;;\nesac\n\nARG=\"${1:-\"\"}\"\n\n\n(cd interop && cargo build --bins)\n\nSERVER=\"interop/bin/server_${OS}_amd64${EXT}\"\n\nTLS_CA=\"interop/data/ca.pem\"\nTLS_CRT=\"interop/data/server1.pem\"\nTLS_KEY=\"interop/data/server1.key\"\n\n# run the test server\n./\"${SERVER}\" \"${ARG}\" --tls_cert_file $TLS_CRT --tls_key_file $TLS_KEY &\nSERVER_PID=$!\necho \":; started grpc-go test server.\"\n\ncleanup() {\n  echo \":; killing test server ${SERVER_PID}\"\n  kill \"${SERVER_PID}\" || true\n}\n\n# trap exits to make sure we kill the server process when the script exits,\n# regardless of why (errors, SIGTERM, etc).\ntrap cleanup EXIT\n\nsleep 3\n\nTARGET_DIR=\"$(cargo metadata --format-version 1 | jq -r '.target_directory')\"\n\"${TARGET_DIR}/debug/client\" --codec=prost --test_case=\"${JOINED_TEST_CASES}\" \"${ARG}\"\n\n# Test a grpc rust client against a Go server.\n\"${TARGET_DIR}/debug/client\" --codec=protobuf --test_case=\"${JOINED_TEST_CASES}\" ${ARG}\n\necho \":; killing test server\"; kill \"${SERVER_PID}\";\necho \"Waiting for test server to exit...\"\nwhile kill -0 ${SERVER_PID} 2> /dev/null; do\n    sleep 0.5\ndone\n\nCODECS=(\"prost\" \"protobuf\")\n\nfor CODEC in \"${CODECS[@]}\"; do\n    # run the test server\n    \"${TARGET_DIR}/debug/server\" \"${ARG}\" --codec \"${CODEC}\" &\n    SERVER_PID=$!\n    echo \":; started tonic test server with the ${CODEC} codec.\"\n\n    sleep 3\n\n    \"${TARGET_DIR}/debug/client\" --codec=prost --test_case=\"${JOINED_TEST_CASES}\" \"${ARG}\"\n\n    # Run client test cases\n    if [ -n \"${ARG:-}\" ]; then\n      TLS_ARRAY=( \\\n        -use_tls \\\n        -use_test_ca \\\n        -server_host_override=foo.test.google.fr \\\n        -ca_file=\"${TLS_CA}\" \\\n      )\n    else\n      TLS_ARRAY=()\n    fi\n\n    for CASE in \"${TEST_CASES[@]}\"; do\n      flags=( \"-test_case=${CASE}\" )\n      # Avoid unbound variable errors on MacOS with bash version < 4.4.\n      # See: https://stackoverflow.com/a/61551944\n      flags+=( ${TLS_ARRAY[@]+\"${TLS_ARRAY[@]}\"} )\n      interop/bin/client_\"${OS}\"_amd64\"${EXT}\" \"${flags[@]}\"\n    done\n\n    echo \":; killing test server\"; kill \"${SERVER_PID}\";\n    echo \"Waiting for test server to exit...\"\n    while kill -0 ${SERVER_PID} 2> /dev/null; do\n        sleep 0.5\n    done\ndone\n"
  },
  {
    "path": "interop/update_binaries.sh",
    "content": "#!/bin/bash\nset -e\n\n# This script updates server and client go binaries for interop tests.\n# It clones grpc-go, compiles interop clients and servers for linux, windows\n# and macos and finally deletes the cloned repo.\n#\n# It is not meant to be executed on every test run or CI and should run from\n# inside tonic/interop.\n\ncommand -v go >/dev/null 2>&1 || {\n  echo >&2 \"go executable is not available\"\n  exit 1\n}\n\nif [ ! -d \"./grpc-go\" ]; then\n  git clone https://github.com/grpc/grpc-go.git\nfi\n\ncd grpc-go\n\nPLATFORMS=\"darwin linux windows\"\nROLES=\"client server\"\nARCH=amd64\n\nfor ROLE in $ROLES; do\n  for OS in $PLATFORMS; do\n    FILENAME=\"${ROLE}_${OS}_${ARCH}\"\n    if [[ \"${OS}\" == \"windows\" ]]; then FILENAME=\"${FILENAME}.exe\"; fi\n    GOOS=$OS GOARCH=$ARCH go build -o \"../bin/$FILENAME\" \"./interop/$ROLE\"\n  done\ndone\n\nrm -rf ../grpc-go\n"
  },
  {
    "path": "prepare-release.sh",
    "content": "#!/usr/bin/env bash\n\n# Script which automates modifying source version fields, and creating a release\n# commit and tag. The commit and tag are not automatically pushed, nor are the\n# crates published (see publish-release.sh).\n\nset -ex\n\nif [ \"$#\" -ne 1 ]\nthen\n  echo \"Usage: $0 <version>\"\n  exit 1\nfi\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\nVERSION=\"$1\"\nMINOR=\"$( echo \"${VERSION}\" | cut -d\\. -f1-2 )\"\n\nVERSION_MATCHER=\"([a-z0-9\\\\.-]+)\"\nTONIC_CRATE_MATCHER=\"(tonic|tonic-[a-z]+)\"\n\n# Update the README.md.\nsed -i -E \"s/${TONIC_CRATE_MATCHER} = \\\"${VERSION_MATCHER}\\\"/\\1 = \\\"${MINOR}\\\"/\" \"$DIR/examples/helloworld-tutorial.md\"\nsed -i -E \"s/${TONIC_CRATE_MATCHER} = \\\"${VERSION_MATCHER}\\\"/\\1 = \\\"${MINOR}\\\"/\" \"$DIR/examples/routeguide-tutorial.md\"\n\nCRATES=( \\\n  \"tonic\" \\\n  \"tonic-build\" \\\n  \"tonic-types\" \\\n  \"tonic-reflection\" \\\n  \"tonic-health\" \\\n  \"tonic-web\" \\\n  \"tonic-prost\" \\\n  \"tonic-prost-build\" \\\n)\n\nfor CRATE in \"${CRATES[@]}\"; do\n  # Update Cargo.toml version fields.\n  sed -i -E \"s/^version = \\\"${VERSION_MATCHER}\\\"$/version = \\\"${VERSION}\\\"/\" \\\n    \"$DIR/$CRATE/Cargo.toml\"\ndone\n"
  },
  {
    "path": "protoc-gen-rust-grpc/.bazelrc",
    "content": "# Define a custom config for common Unix-like flags\nbuild:unix --cxxopt=-std=c++17\nbuild:unix --host_cxxopt=-std=c++17\n\n# Inherit the common 'unix' flags for both macOS and Linux\nbuild:macos --config=unix\nbuild:linux --config=unix\n\n# Windows flags remain as they are\nbuild:windows --cxxopt=/std:c++17\nbuild:windows --host_cxxopt=/std:c++17\nbuild:windows --define=protobuf_allow_msvc=true\n\n"
  },
  {
    "path": "protoc-gen-rust-grpc/.gitignore",
    "content": "# Bazel\nbazel-bin\nbazel-genfiles\nbazel-out\nbazel-protoc-gen-rust-grpc\nbazel-testlogs\nMODULE.bazel.lock\n\nbuild/*\nCMakeFiles/*\n"
  },
  {
    "path": "protoc-gen-rust-grpc/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.14)\nproject(protoc-gen-rust-grpc LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\nif(MINGW)\n    add_compile_options(\"-Wa,-mbig-obj\")\nelseif(MSVC)\n    add_compile_options(\"/bigobj\")\nendif()\n\n# Options\nset(PROTOBUF_VERSION \"33.0\" CACHE STRING \"Version of protobuf to download\")\noption(BUILD_SHARED_LIBS \"Build shared libraries\" OFF)\n\n# Add cmake directory to module path\nlist(APPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake\")\n\n# Include modules\ninclude(FetchContent)\ninclude(FetchProtobuf)\n\n# Download and configure protobuf\nfetch_protobuf(${PROTOBUF_VERSION})\n\n# Download and configure abseil\n# Abseil version that's compatible with protobuf\nset(ABSEIL_VERSION \"20240722.0\")\nset(ABSEIL_URL \"https://github.com/abseil/abseil-cpp/archive/refs/tags/${ABSEIL_VERSION}.tar.gz\")\n\nmessage(STATUS \"Downloading abseil-cpp ${ABSEIL_VERSION}\")\n\nFetchContent_Declare(\n    absl\n    URL ${ABSEIL_URL}\n    URL_HASH SHA256=f50e5ac311a81382da7fa75b97310e4b9006474f9560ac46f54a9967f07d4ae3\n    DOWNLOAD_EXTRACT_TIMESTAMP TRUE\n)\n\n# Set abseil build options\nset(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL \"\" FORCE)\nset(ABSL_BUILD_TESTING OFF CACHE BOOL \"\" FORCE)\nset(BUILD_TESTING OFF CACHE BOOL \"\" FORCE)\n\n# Force using the fetched abseil instead of system abseil\nset(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)\nset(absl_DIR \"${CMAKE_CURRENT_BINARY_DIR}/_deps/absl-build\" CACHE PATH \"\" FORCE)\n# Prevent finding system libraries\nset(CMAKE_PREFIX_PATH \"\" CACHE STRING \"\" FORCE)\n\nFetchContent_MakeAvailable(absl)\n\n# Add the protoc-gen-rust-grpc executable\nadd_executable(protoc-gen-rust-grpc\n    src/grpc_rust_plugin.cc\n    src/grpc_rust_generator.cc\n    src/grpc_rust_generator.h\n)\n\n# Link against protobuf and abseil\ntarget_link_libraries(protoc-gen-rust-grpc\n    PRIVATE\n        protobuf::libprotoc\n        protobuf::libprotobuf\n        absl::flat_hash_map\n        absl::strings\n        absl::string_view\n)\n\n# Include directories\ntarget_include_directories(protoc-gen-rust-grpc\n    PRIVATE\n        ${protobuf_SOURCE_DIR}/src\n        ${CMAKE_CURRENT_SOURCE_DIR}\n)\n\n# Set output directory\nset_target_properties(protoc-gen-rust-grpc\n    PROPERTIES\n        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin\n)\n\n# Add protoc executable as a custom target that copies the built protoc\n# We explicitly name it \"protoc\" without version suffix\nif(WIN32)\n    set(PROTOC_OUTPUT_NAME \"protoc.exe\")\nelse()\n    set(PROTOC_OUTPUT_NAME \"protoc\")\nendif()\n\nadd_custom_target(copy-protoc ALL\n    COMMAND ${CMAKE_COMMAND} -E copy_if_different\n        $<TARGET_FILE:protoc>\n        ${CMAKE_BINARY_DIR}/bin/${PROTOC_OUTPUT_NAME}\n    DEPENDS protoc\n    COMMENT \"Copying protoc to output directory\"\n)\n\n# Installation rules\ninstall(TARGETS protoc-gen-rust-grpc\n    RUNTIME DESTINATION bin\n)\ninstall(PROGRAMS ${CMAKE_BINARY_DIR}/bin/${PROTOC_OUTPUT_NAME}\n    DESTINATION bin\n)\n\n# Print summary\nmessage(STATUS \"\")\nmessage(STATUS \"protoc-gen-rust-grpc configuration summary:\")\nmessage(STATUS \"  Protobuf version: ${PROTOBUF_VERSION}\")\nmessage(STATUS \"  Abseil version: ${ABSEIL_VERSION}\")\nmessage(STATUS \"  Build type: ${CMAKE_BUILD_TYPE}\")\nmessage(STATUS \"  C++ standard: ${CMAKE_CXX_STANDARD}\")\nmessage(STATUS \"  Output directory: ${CMAKE_BINARY_DIR}/bin\")\nmessage(STATUS \"  Binaries to build: protoc, protoc-gen-rust-grpc\")\n"
  },
  {
    "path": "protoc-gen-rust-grpc/README.md",
    "content": "# protoc-gen-rust-grpc\n\nA protoc plugin that generates Rust gRPC service code using the Tonic framework.\n\n## Build\n\nRequirements:\n- CMake 3.14 or higher\n- C++17 compatible compiler\n\n```bash\n# Create build directory\nmkdir build && cd build\n\n# Configure (downloads protobuf and dependencies automatically)\ncmake .. -DCMAKE_BUILD_TYPE=Release\n\n# Build\ncmake --build . --parallel\n\n# Optional: specify a different protobuf version\ncmake .. -DCMAKE_BUILD_TYPE=Release -DPROTOBUF_VERSION=28.3\n```\n\nThe binaries will be in `build/bin/`:\n- `protoc` - The protobuf compiler\n- `protoc-gen-rust-grpc` - The Rust gRPC code generator plugin\n\n## Usage\n\n**Note:** It's generally recommended to use `tonic_protobuf_build::CodeGen` and/or `protobuf_codegen::CodeGen` instead of invoking `protoc` directly.\n\n```bash\n# Add the plugin to PATH\nexport PATH=\"$PWD/build/bin:$PATH\"\n\n# Generate Rust gRPC code\nprotoc \\\n  --rust_opt=\"experimental-codegen=enabled,kernel=upb\" \\\n  --rust_out=./generated \\\n  --rust-grpc_out=./generated \\\n  your_service.proto\n```\n\n## Available Options\n\n* `message_module_path=PATH` (optional): Specifies the Rust path to the module where Protobuf messages are defined.\n  * Default: `self`\n  * Example: `message_module_path=crate::pb::messages`\n\n* `crate_mapping=PATH` (optional): Specifies the path to a crate mapping file for multi-crate projects."
  },
  {
    "path": "protoc-gen-rust-grpc/cmake/FetchProtobuf.cmake",
    "content": "# FetchProtobuf.cmake - Helper to download and configure protobuf\n#\n# This file provides a function to download protobuf from GitHub releases\n# with automatic hash verification.\n\nfunction(fetch_protobuf VERSION)\n    include(FetchContent)\n\n    # Map of known protobuf versions to their SHA256 hashes\n    # You can add more versions here as needed\n    if(VERSION STREQUAL \"33.0\")\n        set(HASH \"cbc536064706b628dcfe507bef386ef3e2214d563657612296f1781aa155ee07\")\n    elseif(VERSION STREQUAL \"32.0\")\n        set(HASH \"9dfdf08129f025a6c5802613b8ee1395044fecb71d38210ca59ecad283ef68bb\")\n    elseif(VERSION STREQUAL \"31.1\")\n        set(HASH \"12bfd76d27b9ac3d65c00966901609e020481b9474ef75c7ff4601ac06fa0b82\")\n    elseif(VERSION STREQUAL \"28.3\")\n        set(HASH \"35224c34cdc65a0b59938f62aebdc99c6285fc67f5c0ba5e8273b66179e1c106\")\n    elseif(VERSION STREQUAL \"27.5\")\n        set(HASH \"5c56c6be6ba37b0551f9c7b69e4e80d3df30bd962aacaed5ebf3e4df4bb0f746\")\n    else()\n        message(WARNING \"Unknown protobuf version ${VERSION}, downloading without hash verification\")\n        set(HASH \"\")\n    endif()\n\n    set(PROTOBUF_URL \"https://github.com/protocolbuffers/protobuf/releases/download/v${VERSION}/protobuf-${VERSION}.tar.gz\")\n\n    message(STATUS \"Fetching protobuf ${VERSION} from ${PROTOBUF_URL}\")\n\n    if(HASH)\n        FetchContent_Declare(\n            protobuf\n            URL ${PROTOBUF_URL}\n            URL_HASH SHA256=${HASH}\n            DOWNLOAD_EXTRACT_TIMESTAMP TRUE\n        )\n    else()\n        FetchContent_Declare(\n            protobuf\n            URL ${PROTOBUF_URL}\n            DOWNLOAD_EXTRACT_TIMESTAMP TRUE\n        )\n    endif()\n\n    # Set protobuf build options before FetchContent_MakeAvailable\n    set(protobuf_BUILD_TESTS OFF CACHE BOOL \"\" FORCE)\n    set(protobuf_BUILD_CONFORMANCE OFF CACHE BOOL \"\" FORCE)\n    set(protobuf_BUILD_EXAMPLES OFF CACHE BOOL \"\" FORCE)\n    set(protobuf_BUILD_PROTOC_BINARIES ON CACHE BOOL \"\" FORCE)\n    set(protobuf_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS} CACHE BOOL \"\" FORCE)\n    set(protobuf_INSTALL OFF CACHE BOOL \"\" FORCE)\n    set(protobuf_WITH_ZLIB OFF CACHE BOOL \"\" FORCE)\n    set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL \"\" FORCE)\n\n    FetchContent_MakeAvailable(protobuf)\n\n    # Export the source directory for later use\n    set(protobuf_SOURCE_DIR ${protobuf_SOURCE_DIR} PARENT_SCOPE)\nendfunction()\n"
  },
  {
    "path": "protoc-gen-rust-grpc/src/BUILD",
    "content": "# Copyright 2025 gRPC authors.\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to\n# deal in the Software without restriction, including without limitation the\n# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n# sell copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n# IN THE SOFTWARE.\n\ncc_binary(\n    name = \"protoc-gen-rust-grpc\",\n    srcs = [\n        \"grpc_rust_plugin.cc\",\n        \"grpc_rust_generator.h\",\n        \"grpc_rust_generator.cc\",\n    ],\n    visibility = [\"//visibility:public\"],\n    deps = [\n        \"@com_google_protobuf//:protoc_lib\",\n    ],\n)\n"
  },
  {
    "path": "protoc-gen-rust-grpc/src/grpc_rust_generator.cc",
    "content": "// Copyright 2025 gRPC authors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n// IN THE SOFTWARE.\n\n#include \"src/grpc_rust_generator.h\"\n\n#include <string_view>\n#include <vector>\n\n#include \"absl/strings/str_join.h\"\n#include \"absl/strings/str_replace.h\"\n#include \"absl/strings/str_split.h\"\n#include \"absl/strings/string_view.h\"\n#include \"google/protobuf/compiler/rust/naming.h\"\n#include \"google/protobuf/descriptor.h\"\n#include \"google/protobuf/descriptor.pb.h\"\n\nnamespace rust_grpc_generator {\nnamespace protobuf = google::protobuf;\nnamespace rust = protobuf::compiler::rust;\n\nusing protobuf::Descriptor;\nusing protobuf::FileDescriptor;\nusing protobuf::MethodDescriptor;\nusing protobuf::ServiceDescriptor;\nusing protobuf::SourceLocation;\nusing protobuf::io::Printer;\n\nnamespace {\ntemplate <typename DescriptorType>\nstd::string GrpcGetCommentsForDescriptor(const DescriptorType *descriptor) {\n  SourceLocation location;\n  if (descriptor->GetSourceLocation(&location)) {\n    return location.leading_comments.empty() ? location.trailing_comments\n                                             : location.leading_comments;\n  }\n  return \"\";\n}\n\nstd::string RustModuleForContainingType(const GrpcOpts &opts,\n                                        const Descriptor *containing_type,\n                                        const FileDescriptor &file) {\n  std::vector<std::string> modules;\n  // Innermost to outermost order.\n  const Descriptor *parent = containing_type;\n  while (parent != nullptr) {\n    modules.push_back(rust::RsSafeName(rust::CamelToSnakeCase(parent->name())));\n    parent = parent->containing_type();\n  }\n\n  // Reverse the vector to get submodules in outer-to-inner order).\n  std::reverse(modules.begin(), modules.end());\n\n  // If there are any modules at all, push an empty string on the end so that\n  // we get the trailing ::\n  if (!modules.empty()) {\n    modules.push_back(\"\");\n  }\n\n  std::string crate_relative = absl::StrJoin(modules, \"::\");\n\n  if (opts.IsFileInCurrentCrate(file)) {\n    return crate_relative;\n  }\n  std::string crate_name =\n      absl::StrCat(\"::\", rust::RsSafeName(opts.GetCrateName(file.name())));\n\n  return absl::StrCat(crate_name, \"::\", crate_relative);\n}\n\nstd::string RsTypePathWithinMessageModule(const GrpcOpts &opts,\n                                          const Descriptor &msg) {\n  return absl::StrCat(\n      RustModuleForContainingType(opts, msg.containing_type(), *msg.file()),\n      rust::RsSafeName(msg.name()));\n}\n\nstd::string RsTypePath(const Descriptor &msg, const GrpcOpts &opts, int depth) {\n  std::string path_within_module = RsTypePathWithinMessageModule(opts, msg);\n  if (!opts.IsFileInCurrentCrate(*msg.file())) {\n    return path_within_module;\n  }\n  std::string path_to_message_module = opts.GetMessageModulePath() + \"::\";\n  if (path_to_message_module == \"self::\") {\n    path_to_message_module = \"\";\n  }\n\n  // If the path to the message module is defined from the crate or global\n  // root, we don't need to add a prefix of \"super::\"s.\n  if (absl::StartsWith(path_to_message_module, \"crate::\") ||\n      absl::StartsWith(path_to_message_module, \"::\")) {\n    depth = 0;\n  }\n  std::string prefix = \"\";\n  for (int i = 0; i < depth; ++i) {\n    prefix += \"super::\";\n  }\n  return prefix + path_to_message_module + std::string(path_within_module);\n}\n\nabsl::Status ReadFileToString(const absl::string_view name, std::string *output,\n                              bool text_mode) {\n  char buffer[1024];\n  FILE *file = fopen(name.data(), text_mode ? \"rt\" : \"rb\");\n  if (file == nullptr)\n    return absl::NotFoundError(\"Could not open file\");\n\n  while (true) {\n    size_t n = fread(buffer, 1, sizeof(buffer), file);\n    if (n <= 0)\n      break;\n    output->append(buffer, n);\n  }\n\n  int error = ferror(file);\n  if (fclose(file) != 0)\n    return absl::InternalError(\"Failed to close file\");\n  if (error != 0) {\n    return absl::ErrnoToStatus(error,\n                               absl::StrCat(\"Failed to read the file \", name,\n                                            \". Error code: \", error));\n  }\n  return absl::OkStatus();\n}\n} // namespace\n\nabsl::StatusOr<absl::flat_hash_map<std::string, std::string>>\nGetImportPathToCrateNameMap(const absl::string_view mapping_file_path) {\n  absl::flat_hash_map<std::string, std::string> mapping;\n  std::string mapping_contents;\n  absl::Status status =\n      ReadFileToString(mapping_file_path, &mapping_contents, true);\n  if (!status.ok()) {\n    return status;\n  }\n\n  std::vector<absl::string_view> lines =\n      absl::StrSplit(mapping_contents, '\\n', absl::SkipEmpty());\n  size_t len = lines.size();\n\n  size_t idx = 0;\n  while (idx < len) {\n    absl::string_view crate_name = lines[idx++];\n    size_t files_cnt;\n    if (!absl::SimpleAtoi(lines[idx++], &files_cnt)) {\n      return absl::InvalidArgumentError(\n          \"Couldn't parse number of import paths in mapping file\");\n    }\n    for (size_t i = 0; i < files_cnt; ++i) {\n      mapping.insert({std::string(lines[idx++]), std::string(crate_name)});\n    }\n  }\n  return mapping;\n}\n\n// Method generation abstraction.\n//\n// Each service contains a set of generic methods that will be used by codegen\n// to generate abstraction implementations for the provided methods.\nclass Method {\npublic:\n  Method() = delete;\n\n  explicit Method(const MethodDescriptor *method) : method_(method) {}\n\n  // The name of the method in Rust style.\n  std::string Name() const {\n    return rust::RsSafeName(rust::CamelToSnakeCase(method_->name()));\n  };\n\n  // The fully-qualified name of the method, scope delimited by periods.\n  absl::string_view FullName() const { return method_->full_name(); }\n\n  // The name of the method as it appears in the .proto file.\n  absl::string_view ProtoFieldName() const { return method_->name(); };\n\n  // Checks if the method is streamed by the client.\n  bool IsClientStreaming() const { return method_->client_streaming(); };\n\n  // Checks if the method is streamed by the server.\n  bool IsServerStreaming() const { return method_->server_streaming(); };\n\n  // Get comments about this method.\n  std::string Comment() const { return GrpcGetCommentsForDescriptor(method_); };\n\n  // Checks if the method is deprecated. Default is false.\n  bool IsDeprecated() const { return method_->options().deprecated(); }\n\n  // Returns the Rust type name of request message.\n  std::string RequestName(const GrpcOpts &opts, int depth) const {\n    const Descriptor *input = method_->input_type();\n    return RsTypePath(*input, opts, depth);\n  };\n\n  // Returns the Rust type name of response message.\n  std::string ResponseName(const GrpcOpts &opts, int depth) const {\n    const Descriptor *output = method_->output_type();\n    return RsTypePath(*output, opts, depth);\n  };\n\nprivate:\n  const MethodDescriptor *method_;\n};\n\n// Service generation abstraction.\n//\n// This class is an interface that can be implemented and consumed\n// by client and server generators to allow any codegen module\n// to generate service abstractions.\nclass Service {\npublic:\n  Service() = delete;\n\n  explicit Service(const ServiceDescriptor *service) : service_(service) {}\n\n  // The name of the service, not including its containing scope.\n  std::string Name() const {\n    return rust::RsSafeName(rust::SnakeToUpperCamelCase(service_->name()));\n  };\n\n  // The fully-qualified name of the service, scope delimited by periods.\n  absl::string_view FullName() const { return service_->full_name(); };\n\n  // Returns a list of Methods provided by the service.\n  std::vector<Method> Methods() const {\n    std::vector<Method> ret;\n    int methods_count = service_->method_count();\n    ret.reserve(methods_count);\n    for (int i = 0; i < methods_count; ++i) {\n      ret.push_back(Method(service_->method(i)));\n    }\n    return ret;\n  };\n\n  // Get comments about this service.\n  virtual std::string Comment() const {\n    return GrpcGetCommentsForDescriptor(service_);\n  };\n\nprivate:\n  const ServiceDescriptor *service_;\n};\n\n// Formats the full path for a method call. Returns the formatted method path\n// (e.g., \"/package.MyService/MyMethod\")\nstatic std::string FormatMethodPath(const Service &service,\n                                    const Method &method) {\n  return absl::StrFormat(\"/%s/%s\", service.FullName(), method.ProtoFieldName());\n}\n\nstatic std::string SanitizeForRustDoc(absl::string_view raw_comment) {\n  // 1. Escape the escape character itself first.\n  std::string sanitized = absl::StrReplaceAll(raw_comment, {{\"\\\\\", \"\\\\\\\\\"}});\n\n  // 2. Escape Markdown and Rustdoc special characters.\n  sanitized = absl::StrReplaceAll(sanitized, {\n                                                 {\"`\", \"\\\\`\"},\n                                                 {\"*\", \"\\\\*\"},\n                                                 {\"_\", \"\\\\_\"},\n                                                 {\"[\", \"\\\\[\"},\n                                                 {\"]\", \"\\\\]\"},\n                                                 {\"#\", \"\\\\#\"},\n                                                 {\"<\", \"\\\\<\"},\n                                                 {\">\", \"\\\\>\"},\n                                             });\n\n  return sanitized;\n}\n\nstatic std::string ProtoCommentToRustDoc(absl::string_view proto_comment) {\n  std::string rust_doc;\n  std::vector<std::string_view> lines = absl::StrSplit(proto_comment, '\\n');\n  // Remove trailing empty lines.\n  while (!lines.empty() && lines.back().empty()) {\n    lines.pop_back();\n  }\n  for (const absl::string_view &line : lines) {\n    // Preserve empty lines.\n    if (line.empty()) {\n      rust_doc += (\"///\\n\");\n    } else {\n      rust_doc += absl::StrFormat(\"///%s\\n\", SanitizeForRustDoc(line));\n    }\n  }\n  return rust_doc;\n}\n\nstatic void GenerateDeprecated(Printer &ctx) { ctx.Emit(\"#[deprecated]\\n\"); }\n\nnamespace client {\n\nstatic void GenerateMethods(Printer &printer, const Service &service,\n                            const GrpcOpts &opts) {\n  static const std::string unary_format = R\"rs(\n    pub async fn $ident$(\n        &mut self,\n        request: impl tonic::IntoRequest<$request$>,\n    ) -> std::result::Result<tonic::Response<$response$>, tonic::Status> {\n       self.inner.ready().await.map_err(|e| {\n           tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n       })?;\n       let codec = $codec_name$::default();\n       let path = http::uri::PathAndQuery::from_static(\"$path$\");\n       let mut req = request.into_request();\n       req.extensions_mut().insert(GrpcMethod::new(\"$service_name$\", \"$method_name$\"));\n       self.inner.unary(req, path, codec).await\n    }\n    )rs\";\n\n  static const std::string server_streaming_format = R\"rs(\n        pub async fn $ident$(\n            &mut self,\n            request: impl tonic::IntoRequest<$request$>,\n        ) -> std::result::Result<tonic::Response<tonic::codec::Streaming<$response$>>, tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n            })?;\n            let codec = $codec_name$::default();\n            let path = http::uri::PathAndQuery::from_static(\"$path$\");\n            let mut req = request.into_request();\n            req.extensions_mut().insert(GrpcMethod::new(\"$service_name$\", \"$method_name$\"));\n            self.inner.server_streaming(req, path, codec).await\n        }\n      )rs\";\n\n  static const std::string client_streaming_format = R\"rs(\n        pub async fn $ident$(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<Message = $request$>\n        ) -> std::result::Result<tonic::Response<$response$>, tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n            })?;\n            let codec = $codec_name$::default();\n            let path = http::uri::PathAndQuery::from_static(\"$path$\");\n            let mut req = request.into_streaming_request();\n            req.extensions_mut().insert(GrpcMethod::new(\"$service_name$\", \"$method_name$\"));\n            self.inner.client_streaming(req, path, codec).await\n        }\n      )rs\";\n\n  static const std::string streaming_format = R\"rs(\n        pub async fn $ident$(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<Message = $request$>\n        ) -> std::result::Result<tonic::Response<tonic::codec::Streaming<$response$>>, tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n            })?;\n            let codec = $codec_name$::default();\n            let path = http::uri::PathAndQuery::from_static(\"$path$\");\n            let mut req = request.into_streaming_request();\n            req.extensions_mut().insert(GrpcMethod::new(\"$service_name$\", \"$method_name$\"));\n            self.inner.streaming(req, path, codec).await\n        }\n      )rs\";\n\n  const std::vector<Method> methods = service.Methods();\n  for (const Method &method : methods) {\n    printer.Emit(ProtoCommentToRustDoc(method.Comment()));\n    if (method.IsDeprecated()) {\n      GenerateDeprecated(printer);\n    }\n    const std::string request_type = method.RequestName(opts, 1);\n    const std::string response_type = method.ResponseName(opts, 1);\n    {\n      auto vars =\n          printer.WithVars({{\"codec_name\", \"tonic_protobuf::ProtoCodec\"},\n                            {\"ident\", method.Name()},\n                            {\"request\", request_type},\n                            {\"response\", response_type},\n                            {\"service_name\", service.FullName()},\n                            {\"path\", FormatMethodPath(service, method)},\n                            {\"method_name\", method.ProtoFieldName()}});\n\n      if (!method.IsClientStreaming() && !method.IsServerStreaming()) {\n        printer.Emit(unary_format);\n      } else if (!method.IsClientStreaming() && method.IsServerStreaming()) {\n        printer.Emit(server_streaming_format);\n      } else if (method.IsClientStreaming() && !method.IsServerStreaming()) {\n        printer.Emit(client_streaming_format);\n      } else {\n        printer.Emit(streaming_format);\n      }\n      if (&method != &methods.back()) {\n        printer.Emit(\"\\n\");\n      }\n    }\n  }\n}\n\nstatic void GenerateClient(const Service &service, Printer &printer,\n                           const GrpcOpts &opts) {\n  std::string service_ident = absl::StrFormat(\"%sClient\", service.Name());\n  std::string client_mod =\n      absl::StrFormat(\"%s_client\", rust::CamelToSnakeCase(service.Name()));\n  printer.Emit(\n      {\n          {\"client_mod\", client_mod},\n          {\"service_ident\", service_ident},\n          {\"service_doc\",\n           [&] { printer.Emit(ProtoCommentToRustDoc(service.Comment())); }},\n          {\"methods\", [&] { GenerateMethods(printer, service, opts); }},\n      },\n      R\"rs(\n      /// Generated client implementations.\n      pub mod $client_mod$ {\n          #![allow(\n              unused_variables,\n              dead_code,\n              missing_docs,\n              clippy::wildcard_imports,\n              // will trigger if compression is disabled\n              clippy::let_unit_value,\n          )]\n          use tonic::codegen::*;\n          use tonic::codegen::http::Uri;\n\n          $service_doc$\n          #[derive(Debug, Clone)]\n          pub struct $service_ident$<T> {\n              inner: tonic::client::Grpc<T>,\n          }\n\n          impl<T> $service_ident$<T>\n          where\n              T: tonic::client::GrpcService<tonic::body::Body>,\n              T::Error: Into<StdError>,\n              T::ResponseBody: Body<Data = Bytes> + std::marker::Send  +\n              'static, <T::ResponseBody as Body>::Error: Into<StdError> +\n              std::marker::Send,\n          {\n              pub fn new(inner: T) -> Self {\n                  let inner = tonic::client::Grpc::new(inner);\n                  Self { inner }\n              }\n\n              pub fn with_origin(inner: T, origin: Uri) -> Self {\n                  let inner = tonic::client::Grpc::with_origin(inner, origin);\n                  Self { inner }\n              }\n\n              pub fn with_interceptor<F>(inner: T, interceptor: F) ->\n              $service_ident$<InterceptedService<T, F>> where\n                  F: tonic::service::Interceptor,\n                  T::ResponseBody: Default,\n                  T: tonic::codegen::Service<\n                      http::Request<tonic::body::Body>,\n                      Response = http::Response<<T as\n                      tonic::client::GrpcService<tonic::body::Body>>::ResponseBody>\n                  >,\n                  <T as\n                  tonic::codegen::Service<http::Request<tonic::body::Body>>>::Error:\n                  Into<StdError> + std::marker::Send + std::marker::Sync,\n              {\n                  $service_ident$::new(InterceptedService::new(inner, interceptor))\n              }\n\n              /// Compress requests with the given encoding.\n              ///\n              /// This requires the server to support it otherwise it might respond with an\n              /// error.\n              #[must_use]\n              pub fn send_compressed(mut self, encoding: CompressionEncoding)\n              -> Self {\n                  self.inner = self.inner.send_compressed(encoding);\n                  self\n              }\n\n              /// Enable decompressing responses.\n              #[must_use]\n              pub fn accept_compressed(mut self, encoding:\n              CompressionEncoding) -> Self {\n                  self.inner = self.inner.accept_compressed(encoding);\n                  self\n              }\n\n              /// Limits the maximum size of a decoded message.\n              ///\n              /// Default: `4MB`\n              #[must_use]\n              pub fn max_decoding_message_size(mut self, limit: usize) ->\n              Self {\n                  self.inner = self.inner.max_decoding_message_size(limit);\n                  self\n              }\n\n              /// Limits the maximum size of an encoded message.\n              ///\n              /// Default: `usize::MAX`\n              #[must_use]\n              pub fn max_encoding_message_size(mut self, limit: usize) ->\n              Self {\n                  self.inner = self.inner.max_encoding_message_size(limit);\n                  self\n              }\n\n              $methods$\n          }\n      })rs\");\n}\n\n} // namespace client\n\nnamespace server {\nstatic void GenerateTraitMethods(Printer &printer, const Service &service,\n                                 const GrpcOpts &opts) {\n  static const std::string unary_format = R\"rs(\n    $method_doc$\n    async fn $name$(&self, request: tonic::Request<$request$>)\n        -> std::result::Result<tonic::Response<$response$>, tonic::Status> {\n        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n    }\n  )rs\";\n\n  static const std::string client_streaming_format = R\"rs(\n    $method_doc$\n    async fn $name$(&self, request: tonic::Request<tonic::Streaming<$request$>>)\n        -> std::result::Result<tonic::Response<$response$>, tonic::Status> {\n        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n    }\n    )rs\";\n\n  static const std::string server_streaming_format = R\"rs(\n    $method_doc$\n    async fn $name$(&self, request: tonic::Request<$request$>)\n        -> std::result::Result<tonic::Response<BoxStream<$response$>>, tonic::Status> {\n        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n    }\n    )rs\";\n\n  static const std::string streaming_format = R\"rs(\n    $method_doc$\n    async fn $name$(&self, request: tonic::Request<tonic::Streaming<$request$>>)\n        -> std::result::Result<tonic::Response<BoxStream<$response$>>, tonic::Status> {\n        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n    }\n    )rs\";\n\n  const std::vector<Method> methods = service.Methods();\n  for (const Method &method : methods) {\n    const std::string request_type = method.RequestName(opts, 1);\n    const std::string response_type = method.ResponseName(opts, 1);\n    auto vars = printer.WithVars({\n        {\"name\", method.Name()},\n        {\"request\", request_type},\n        {\"response\", response_type},\n        {\"method_doc\", ProtoCommentToRustDoc(method.Comment())},\n    });\n    if (!method.IsClientStreaming() && !method.IsServerStreaming()) {\n      printer.Emit(unary_format);\n    } else if (!method.IsClientStreaming() && method.IsServerStreaming()) {\n      printer.Emit(server_streaming_format);\n    } else if (method.IsClientStreaming() && !method.IsServerStreaming()) {\n      printer.Emit(client_streaming_format);\n    } else {\n      printer.Emit(streaming_format);\n    }\n    if (&method != &methods.back()) {\n      printer.Emit(\"\\n\");\n    }\n  }\n}\n\nstatic void GenerateTrait(Printer &printer, const Service &service,\n                          const GrpcOpts &opts) {\n  const std::string trait_doc = ProtoCommentToRustDoc(\n      \" Generated trait containing gRPC methods that should \"\n      \"be implemented for use with \" +\n      service.Name() + \"Server.\");\n  printer.Emit(\n      {\n          {\"trait_doc\", trait_doc},\n          {\"methods\", [&] { GenerateTraitMethods(printer, service, opts); }},\n      },\n      R\"rs(\n    $trait_doc$\n    #[async_trait]\n    pub trait $server_trait$ : std::marker::Send + std::marker::Sync + 'static {\n        $methods$\n    }\n    )rs\");\n}\n\nstatic void GenerateMethods(Printer &printer, const Service &service,\n                            const GrpcOpts &opts) {\n  static const std::string unary_format = R\"rs(\n    #[allow(non_camel_case_types)]\n    struct $service_ident$<T: $server_trait$ >(pub Arc<T>);\n\n    impl<T: $server_trait$> tonic::server::UnaryService<$request$> for $service_ident$<T> {\n        type Response = $response$;\n        type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;\n\n        fn call(&mut self, request: tonic::Request<$request$>) -> Self::Future {\n            let inner = Arc::clone(&self.0);\n            let fut = async move {\n                <T as $server_trait$>::$method_ident$(&inner, request).await\n            };\n            Box::pin(fut)\n        }\n    }\n\n    let accept_compression_encodings = self.accept_compression_encodings;\n    let send_compression_encodings = self.send_compression_encodings;\n    let max_decoding_message_size = self.max_decoding_message_size;\n    let max_encoding_message_size = self.max_encoding_message_size;\n    let inner = self.inner.clone();\n    let fut = async move {\n        let method = $service_ident$(inner);\n        let codec = $codec_name$::default();\n\n        let mut grpc = tonic::server::Grpc::new(codec)\n            .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n            .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n        let res = grpc.unary(method, req).await;\n        Ok(res)\n    };\n\n    Box::pin(fut)\n    )rs\";\n\n  static const std::string server_streaming_format = R\"rs(\n    #[allow(non_camel_case_types)]\n    struct $service_ident$<T: $server_trait$ >(pub Arc<T>);\n\n    impl<T: $server_trait$> tonic::server::ServerStreamingService<$request$> for $service_ident$<T> {\n        type Response = $response$;\n        type ResponseStream = BoxStream<$response$>;\n        type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;\n\n        fn call(&mut self, request: tonic::Request<$request$>) -> Self::Future {\n            let inner = Arc::clone(&self.0);\n            let fut = async move {\n                <T as $server_trait$>::$method_ident$(&inner, request).await\n            };\n            Box::pin(fut)\n        }\n    }\n\n    let accept_compression_encodings = self.accept_compression_encodings;\n    let send_compression_encodings = self.send_compression_encodings;\n    let max_decoding_message_size = self.max_decoding_message_size;\n    let max_encoding_message_size = self.max_encoding_message_size;\n    let inner = self.inner.clone();\n    let fut = async move {\n        let method = $service_ident$(inner);\n        let codec = $codec_name$::default();\n\n        let mut grpc = tonic::server::Grpc::new(codec)\n            .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n            .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n        let res = grpc.server_streaming(method, req).await;\n        Ok(res)\n    };\n\n    Box::pin(fut)\n    )rs\";\n\n  static const std::string client_streaming_format = R\"rs(\n    #[allow(non_camel_case_types)]\n    struct $service_ident$<T: $server_trait$ >(pub Arc<T>);\n\n    impl<T: $server_trait$> tonic::server::ClientStreamingService<$request$> for $service_ident$<T>\n    {\n        type Response = $response$;\n        type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;\n\n        fn call(&mut self, request: tonic::Request<tonic::Streaming<$request$>>) -> Self::Future {\n            let inner = Arc::clone(&self.0);\n            let fut = async move {\n                <T as $server_trait$>::$method_ident$(&inner, request).await\n            };\n            Box::pin(fut)\n        }\n    }\n\n    let accept_compression_encodings = self.accept_compression_encodings;\n    let send_compression_encodings = self.send_compression_encodings;\n    let max_decoding_message_size = self.max_decoding_message_size;\n    let max_encoding_message_size = self.max_encoding_message_size;\n    let inner = self.inner.clone();\n    let fut = async move {\n        let method = $service_ident$(inner);\n        let codec = $codec_name$::default();\n\n        let mut grpc = tonic::server::Grpc::new(codec)\n            .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n            .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n        let res = grpc.client_streaming(method, req).await;\n        Ok(res)\n    };\n\n    Box::pin(fut)\n  )rs\";\n\n  static const std::string streaming_format = R\"rs(\n    #[allow(non_camel_case_types)]\n    struct $service_ident$<T: $server_trait$>(pub Arc<T>);\n\n    impl<T: $server_trait$> tonic::server::StreamingService<$request$> for $service_ident$<T>\n    {\n        type Response = $response$;\n        type ResponseStream = BoxStream<$response$>;\n        type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;\n\n        fn call(&mut self, request: tonic::Request<tonic::Streaming<$request$>>) -> Self::Future {\n            let inner = Arc::clone(&self.0);\n            let fut = async move {\n                <T as $server_trait$>::$method_ident$(&inner, request).await\n            };\n            Box::pin(fut)\n        }\n    }\n\n    let accept_compression_encodings = self.accept_compression_encodings;\n    let send_compression_encodings = self.send_compression_encodings;\n    let max_decoding_message_size = self.max_decoding_message_size;\n    let max_encoding_message_size = self.max_encoding_message_size;\n    let inner = self.inner.clone();\n    let fut = async move {\n        let method = $service_ident$(inner);\n        let codec = $codec_name$::default();\n\n        let mut grpc = tonic::server::Grpc::new(codec)\n            .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n            .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n        let res = grpc.streaming(method, req).await;\n        Ok(res)\n    };\n\n    Box::pin(fut)\n  )rs\";\n\n  const std::vector<Method> methods = service.Methods();\n  for (const Method &method : methods) {\n    const std::string request_type = method.RequestName(opts, 1);\n    const std::string response_type = method.ResponseName(opts, 1);\n    printer.Emit(\n        {\n            {\"codec_name\", \"tonic_protobuf::ProtoCodec\"},\n            {\"service_ident\", method.Name() + \"Svc\"},\n            {\"method_ident\", method.Name()},\n            {\"request\", request_type},\n            {\"response\", response_type},\n            {\"server_trait\", service.Name()},\n            {\"path\", FormatMethodPath(service, method)},\n            {\"method_body\",\n             [&]() {\n               if (!method.IsClientStreaming() && !method.IsServerStreaming()) {\n                 printer.Emit(unary_format);\n               } else if (!method.IsClientStreaming() &&\n                          method.IsServerStreaming()) {\n                 printer.Emit(server_streaming_format);\n               } else if (method.IsClientStreaming() &&\n                          !method.IsServerStreaming()) {\n                 printer.Emit(client_streaming_format);\n               } else {\n                 printer.Emit(streaming_format);\n               }\n             }},\n        },\n        R\"rs(\n    \"$path$\" => {\n        $method_body$\n    }\n    )rs\");\n  }\n}\n\nstatic void GenerateServer(const Service &service, Printer &printer,\n                           const GrpcOpts &opts) {\n\n  std::string server_mod =\n      absl::StrFormat(\"%s_server\", rust::CamelToSnakeCase(service.Name()));\n  printer.Emit(\n      {\n          {\"server_mod\", server_mod},\n          {\"service_doc\", ProtoCommentToRustDoc(service.Comment())},\n          {\"server_service\", service.Name() + \"Server\"},\n          {\"service_name\", service.FullName()},\n          {\"server_trait\", service.Name()},\n          {\"generated_trait\", [&] { GenerateTrait(printer, service, opts); }},\n          {\"methods\", [&] { GenerateMethods(printer, service, opts); }},\n      },\n      R\"rs(\n    /// Generated server implementations.\n    pub mod $server_mod$ {\n        #![allow(\n            unused_variables,\n            dead_code,\n            missing_docs,\n            clippy::wildcard_imports,\n            // will trigger if compression is disabled\n            clippy::let_unit_value,\n        )]\n        use tonic::codegen::*;\n\n        $generated_trait$\n\n        $service_doc$\n        #[derive(Debug)]\n        pub struct $server_service$<T> {\n            inner: Arc<T>,\n            accept_compression_encodings: EnabledCompressionEncodings,\n            send_compression_encodings: EnabledCompressionEncodings,\n            max_decoding_message_size: Option<usize>,\n            max_encoding_message_size: Option<usize>,\n        }\n\n        impl<T> $server_service$<T> {\n            pub fn new(inner: T) -> Self {\n                Self::from_arc(Arc::new(inner))\n            }\n\n            pub fn from_arc(inner: Arc<T>) -> Self {\n                Self {\n                    inner,\n                    accept_compression_encodings: Default::default(),\n                    send_compression_encodings: Default::default(),\n                    max_decoding_message_size: None,\n                    max_encoding_message_size: None,\n                }\n            }\n\n            pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>\n            where\n                F: tonic::service::Interceptor,\n            {\n                InterceptedService::new(Self::new(inner), interceptor)\n            }\n\n            /// Enable decompressing requests with the given encoding.\n            #[must_use]\n            pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n                self.accept_compression_encodings.enable(encoding);\n                self\n            }\n\n            /// Compress responses with the given encoding, if the client supports it.\n            #[must_use]\n            pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n                self.send_compression_encodings.enable(encoding);\n                self\n            }\n\n            /// Limits the maximum size of a decoded message.\n            ///\n            /// Default: `4MB`\n            #[must_use]\n            pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n                self.max_decoding_message_size = Some(limit);\n                self\n            }\n\n            /// Limits the maximum size of an encoded message.\n            ///\n            /// Default: `usize::MAX`\n            #[must_use]\n            pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n                self.max_encoding_message_size = Some(limit);\n                self\n            }\n        }\n\n        impl<T, B> tonic::codegen::Service<http::Request<B>> for $server_service$<T>\n            where\n                T: $server_trait$,\n                B: Body + std::marker::Send + 'static,\n                B::Error: Into<StdError> + std::marker::Send + 'static,\n        {\n            type Response = http::Response<tonic::body::Body>;\n            type Error = std::convert::Infallible;\n            type Future = BoxFuture<Self::Response, Self::Error>;\n\n            fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {\n                Poll::Ready(Ok(()))\n            }\n\n            fn call(&mut self, req: http::Request<B>) -> Self::Future {\n                match req.uri().path() {\n                    $methods$\n\n                    _ => Box::pin(async move {\n                        let mut response = http::Response::new(tonic::body::Body::default());\n                        let headers = response.headers_mut();\n                        headers.insert(tonic::Status::GRPC_STATUS, (tonic::Code::Unimplemented as i32).into());\n                        headers.insert(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE);\n                        Ok(response)\n                    }),\n                }\n            }\n        }\n\n        impl<T> Clone for $server_service$<T> {\n            fn clone(&self) -> Self {\n                let inner = self.inner.clone();\n                Self {\n                    inner,\n                    accept_compression_encodings: self.accept_compression_encodings,\n                    send_compression_encodings: self.send_compression_encodings,\n                    max_decoding_message_size: self.max_decoding_message_size,\n                    max_encoding_message_size: self.max_encoding_message_size,\n                }\n            }\n        }\n\n        /// Generated gRPC service name\n        pub const SERVICE_NAME: &str = \"$service_name$\";\n\n        impl<T> tonic::server::NamedService for $server_service$<T> {\n            const NAME: &'static str = SERVICE_NAME;\n        }\n    }\n  )rs\");\n}\n} // namespace server\n\nvoid GenerateService(protobuf::io::Printer &printer,\n                     const ServiceDescriptor *service_desc,\n                     const GrpcOpts &opts) {\n  Service service = Service(service_desc);\n  client::GenerateClient(service, printer, opts);\n  printer.Print(\"\\n\");\n  server::GenerateServer(service, printer, opts);\n}\n\nstd::string GetRsGrpcFile(const protobuf::FileDescriptor &file) {\n  absl::string_view basename = absl::StripSuffix(file.name(), \".proto\");\n  return absl::StrCat(basename, \"_grpc.pb.rs\");\n}\n\n} // namespace rust_grpc_generator\n"
  },
  {
    "path": "protoc-gen-rust-grpc/src/grpc_rust_generator.h",
    "content": "// Copyright 2025 gRPC authors.\n//\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n// IN THE SOFTWARE.\n\n#ifndef PROTOC_GEN_RUST_GRPC_GRPC_RUST_GENERATOR_H_\n#define PROTOC_GEN_RUST_GRPC_GRPC_RUST_GENERATOR_H_\n\n#include \"absl/log/absl_log.h\"\n#include \"google/protobuf/descriptor.h\"\n\nnamespace rust_grpc_generator {\n\nclass GrpcOpts {\npublic:\n  void SetMessageModulePath(const std::string path) {\n    message_module_path_ = std::move(path);\n  }\n\n  const std::string &GetMessageModulePath() const {\n    return message_module_path_;\n  }\n\n  void SetImportPathToCrateName(\n      const absl::flat_hash_map<std::string, std::string> mapping) {\n    import_path_to_crate_name_ = std::move(mapping);\n  }\n\n  void SetFilesInCurrentCrate(\n      const std::vector<const google::protobuf::FileDescriptor *> files) {\n    files_in_current_crate_ = std::move(files);\n  }\n\n  absl::string_view GetCrateName(absl::string_view import_path) const {\n    auto it = import_path_to_crate_name_.find(import_path);\n    if (it == import_path_to_crate_name_.end()) {\n      ABSL_LOG(ERROR) << \"Path \" << import_path\n                      << \" not found in crate mapping. Crate mapping contains \"\n                      << import_path_to_crate_name_.size() << \" entries:\";\n      for (const auto &entry : import_path_to_crate_name_) {\n        ABSL_LOG(ERROR) << \"  \" << entry.first << \" : \" << entry.second << \"\\n\";\n      }\n      ABSL_LOG(FATAL) << \"Cannot continue with missing crate mapping.\";\n    }\n    return it->second;\n  }\n\n  bool IsFileInCurrentCrate(const google::protobuf::FileDescriptor &f) const {\n    return std::find(files_in_current_crate_.begin(),\n                     files_in_current_crate_.end(),\n                     &f) != files_in_current_crate_.end();\n  }\n\nprivate:\n  // Path of the module containing the generated message code. Defaults to\n  // \"self\", i.e. the message code and service code are present in the same\n  // module.\n  std::string message_module_path_ = \"self\";\n  absl::flat_hash_map<std::string, std::string> import_path_to_crate_name_ = {};\n  std::vector<const google::protobuf::FileDescriptor *>\n      files_in_current_crate_ = {};\n};\n\n// Writes the generated service interface into the given ZeroCopyOutputStream\nvoid GenerateService(google::protobuf::io::Printer &printer,\n                     const google::protobuf::ServiceDescriptor *service,\n                     const GrpcOpts &opts);\n\nstd::string GetRsGrpcFile(const google::protobuf::FileDescriptor &file);\n\n// Returns a map from import path of a .proto file to the name of the crate\n// covering that file.\n//\n// This function parses a .rust_crate_mapping file generated by a build system.\n// The file contains:\n//\n//    <crate_name>\\n\n//    <number of .proto files covered by the proto_library with that name>\\n\n//    <import path of the first .proto file of the crate\\n\n//    ...\n//    <import path of the last .proto file of the crate\\n\nabsl::StatusOr<absl::flat_hash_map<std::string, std::string>>\nGetImportPathToCrateNameMap(const absl::string_view mapping_file_path);\n} // namespace rust_grpc_generator\n\n#endif // PROTOC_GEN_RUST_GRPC_GRPC_RUST_GENERATOR_H_\n"
  },
  {
    "path": "protoc-gen-rust-grpc/src/grpc_rust_plugin.cc",
    "content": "// Copyright 2025 gRPC authors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n// IN THE SOFTWARE.\n\n#include <vector>\n\n#include \"google/protobuf/compiler/code_generator.h\"\n#include \"google/protobuf/compiler/plugin.h\"\n#include \"google/protobuf/io/printer.h\"\n\n#include \"grpc_rust_generator.h\"\n\nnamespace protobuf = google::protobuf;\n\nclass RustGrpcGenerator : public protobuf::compiler::CodeGenerator {\npublic:\n  // Protobuf 5.27 released edition 2023.\n#if GOOGLE_PROTOBUF_VERSION >= 5027000\n  uint64_t GetSupportedFeatures() const override {\n    return Feature::FEATURE_PROTO3_OPTIONAL |\n           Feature::FEATURE_SUPPORTS_EDITIONS;\n  }\n  protobuf::Edition GetMinimumEdition() const override {\n    return protobuf::Edition::EDITION_PROTO2;\n  }\n  protobuf::Edition GetMaximumEdition() const override {\n    return protobuf::Edition::EDITION_2023;\n  }\n#else\n  uint64_t GetSupportedFeatures() const override {\n    return Feature::FEATURE_PROTO3_OPTIONAL;\n  }\n#endif\n\n  bool Generate(const protobuf::FileDescriptor *file,\n                const std::string &parameter,\n                protobuf::compiler::GeneratorContext *context,\n                std::string *error) const override {\n    // Return early to avoid creating an empty output file.\n    if (file->service_count() == 0) {\n      return true;\n    }\n    std::vector<std::pair<std::string, std::string>> options;\n    protobuf::compiler::ParseGeneratorParameter(parameter, &options);\n\n    rust_grpc_generator::GrpcOpts grpc_opts;\n    for (auto opt : options) {\n      if (opt.first == \"message_module_path\") {\n        grpc_opts.SetMessageModulePath(opt.second);\n      } else if (opt.first == \"crate_mapping\") {\n        absl::StatusOr<absl::flat_hash_map<std::string, std::string>>\n            crate_map =\n                rust_grpc_generator::GetImportPathToCrateNameMap(opt.second);\n        if (crate_map.ok()) {\n          grpc_opts.SetImportPathToCrateName(std::move(*crate_map));\n        } else {\n          *error = std::string(crate_map.status().message());\n          return false;\n        }\n      }\n    }\n\n    std::vector<const google::protobuf::FileDescriptor *> files;\n    context->ListParsedFiles(&files);\n    grpc_opts.SetFilesInCurrentCrate(std::move(files));\n\n    auto outfile = absl::WrapUnique(\n        context->Open(rust_grpc_generator::GetRsGrpcFile(*file)));\n    protobuf::io::Printer printer(outfile.get());\n\n    for (int i = 0; i < file->service_count(); ++i) {\n      const protobuf::ServiceDescriptor *service = file->service(i);\n      rust_grpc_generator::GenerateService(printer, service, grpc_opts);\n    }\n    return true;\n  }\n};\n\nint main(int argc, char *argv[]) {\n  RustGrpcGenerator generator;\n  return protobuf::compiler::PluginMain(argc, argv, &generator);\n}\n"
  },
  {
    "path": "publish-release.sh",
    "content": "#!/usr/bin/env bash\n\n# Script which automates publishing a crates.io release of the prost crates.\n\nset -ex\n\nif [ \"$#\" -ne 0 ]\nthen\n  echo \"Usage: $0\"\n  exit 1\nfi\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nCRATES=( \\\n  \"tonic\" \\\n  \"tonic-build\" \\\n  \"tonic-prost\" \\\n  \"tonic-prost-build\" \\\n  \"tonic-types\" \\\n  \"tonic-reflection\" \\\n  \"tonic-health\" \\\n  \"tonic-web\" \\\n)\n\nfor CRATE in \"${CRATES[@]}\"; do\n  pushd \"$DIR/$CRATE\"\n\n  echo \"Publishing $CRATE\"\n\n  cargo publish\n\n  popd\ndone\n"
  },
  {
    "path": "tests/compile/Cargo.toml",
    "content": "[package]\nname = \"test-compile\"\nedition = \"2021\"\nlicense = \"MIT\"\n\n[dependencies]\nprost = \"0.14\"\n\n[dev-dependencies]\nstatic_assertions = \"1\"\ntrybuild = \"1\"\ntonic = {path = \"../../tonic\"}\ntonic-prost = {path = \"../../tonic-prost\"}\n\n[build-dependencies]\ntonic-prost-build = {path = \"../../tonic-prost-build\"}\n"
  },
  {
    "path": "tests/compile/build.rs",
    "content": "fn main() {\n    tonic_prost_build::compile_protos(\"proto/result.proto\").unwrap();\n    tonic_prost_build::compile_protos(\"proto/service.proto\").unwrap();\n    tonic_prost_build::compile_protos(\"proto/stream.proto\").unwrap();\n    tonic_prost_build::compile_protos(\"proto/same_name.proto\").unwrap();\n    tonic_prost_build::compile_protos(\"proto/ambiguous_methods.proto\").unwrap();\n    tonic_prost_build::compile_protos(\"proto/includer.proto\").unwrap();\n    tonic_prost_build::configure()\n        .extern_path(\".root_crate_path.Animal\", \"crate::Animal\")\n        .compile_protos(&[\"proto/root_crate_path.proto\"], &[\".\"])\n        .unwrap();\n    tonic_prost_build::configure()\n        .skip_debug([\"skip_debug.Test\"])\n        .skip_debug([\"skip_debug.Output\"])\n        .build_client(true)\n        .build_server(true)\n        .compile_protos(&[\"proto/skip_debug.proto\"], &[\"proto\"])\n        .unwrap();\n    tonic_prost_build::configure()\n        .use_arc_self(true)\n        .compile_protos(&[\"proto/use_arc_self.proto\"], &[\"proto\"])\n        .unwrap();\n}\n"
  },
  {
    "path": "tests/compile/proto/ambiguous_methods.proto",
    "content": "syntax = \"proto3\";\n\npackage ambiguous_methods;\n\nmessage DropReq {}\nmessage DropResp {}\n\n// The generated stubs can confuse drop and clone\n// with the same method names from Arc,\n// resulting in a compile error.\nservice HelloService {\n    rpc Drop (DropReq) returns (DropResp);\n    rpc Clone (DropReq) returns (DropResp);\n}\n\nservice HelloStreamingService {\n    rpc Drop (DropReq) returns (stream DropResp);\n    rpc Clone (DropReq) returns (stream DropResp);\n}\n"
  },
  {
    "path": "tests/compile/proto/includee.proto",
    "content": "syntax = \"proto3\";\n\npackage includee;\n\nservice Included {\n  rpc SomeMethod(SomeRequest) returns (SomeResponse) {}\n}\n\nmessage SomeRequest {}\n\nmessage SomeResponse {}\n"
  },
  {
    "path": "tests/compile/proto/includer.proto",
    "content": "syntax = \"proto3\";\n\npackage includer;\n\nmessage TopMessage {}\n\nservice TopService {\n  rpc TopMethod(TopMessage) returns (TopMessage) {}\n}\n\nimport \"includee.proto\";\n"
  },
  {
    "path": "tests/compile/proto/result.proto",
    "content": "syntax = \"proto3\";\n\nimport \"google/protobuf/empty.proto\";\n\npackage result;\n\nservice Result {\n  rpc Listen(google.protobuf.Empty) returns (Reply) {}\n}\n\nmessage Reply {\n  int32 step = 1;\n}\n"
  },
  {
    "path": "tests/compile/proto/root_crate_path.proto",
    "content": "syntax = \"proto2\";\n\npackage root_crate_path;\n\nmessage Animal {\n  optional string name = 1;\n}\nservice Zoo {\n  rpc process_animal(Animal) returns (Animal) {};\n}\n"
  },
  {
    "path": "tests/compile/proto/same_name.proto",
    "content": "syntax = \"proto3\";\n\npackage same_name;\n\nservice Foo {\n  rpc Foo(stream FooRequest) returns (stream FooResponse) {}\n}\n\nmessage FooRequest {}\n\nmessage FooResponse {}\n"
  },
  {
    "path": "tests/compile/proto/service.proto",
    "content": "syntax = \"proto3\";\n\npackage foo;\n\nservice Service {\n  rpc Foo(stream FooRequest) returns (stream FooResponse) {}\n}\n\nmessage FooRequest {}\n\nmessage FooResponse {}\n"
  },
  {
    "path": "tests/compile/proto/skip_debug.proto",
    "content": "syntax = \"proto3\";\n\npackage skip_debug;\n\nservice Test {\n  rpc Rpc(Input) returns (Output);\n}\n\nmessage Input {}\n\nmessage Output {}\n"
  },
  {
    "path": "tests/compile/proto/stream.proto",
    "content": "syntax = \"proto3\";\npackage stream;\n\nmessage Message {\n  bool ok = 1;\n}\n\nservice Stream {\n  rpc RunStream(Message) returns (stream Message);\n}\n"
  },
  {
    "path": "tests/compile/proto/use_arc_self.proto",
    "content": "syntax = \"proto3\";\n\npackage use_arc_self;\n\nservice Test {\n  rpc TestRequest(SomeData) returns (SomeData);\n}\n\nmessage SomeData {\n  // include a bunch of data so there actually is something to compress\n  bytes data = 1;\n}\n"
  },
  {
    "path": "tests/compile/src/lib.rs",
    "content": "\n"
  },
  {
    "path": "tests/compile/tests/ui/ambiguous_methods.rs",
    "content": "tonic::include_proto!(\"ambiguous_methods\");\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/includer.rs",
    "content": "mod pb {\n    tonic::include_proto!(\"includer\");\n}\n\n// Ensure that an RPC service, defined before including a file that defines\n// another service in a different protocol buffer package, is not incorrectly\n// cleared from the context of its package.\ntype _Test = dyn pb::top_service_server::TopService;\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/result.rs",
    "content": "tonic::include_proto!(\"result\");\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/root_file_path.rs",
    "content": "#[derive(Clone, PartialEq, ::prost::Message)]\nstruct Animal {\n    #[prost(string, optional, tag = \"1\")]\n    pub name: ::core::option::Option<::prost::alloc::string::String>,\n}\n\nmod pb {\n    tonic::include_proto!(\"root_crate_path\");\n}\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/same_name.rs",
    "content": "tonic::include_proto!(\"foo\");\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/service.rs",
    "content": "tonic::include_proto!(\"foo\");\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/skip_debug.rs",
    "content": "mod pb {\n    tonic::include_proto!(\"skip_debug\");\n}\n\nstatic_assertions::assert_not_impl_all!(pb::Output: std::fmt::Debug);\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/stream.rs",
    "content": "tonic::include_proto!(\"stream\");\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui/use_arc_self.rs",
    "content": "use std::sync::Arc;\nuse tonic::{Request, Response, Status};\n\ntonic::include_proto!(\"use_arc_self\");\n\nstruct Svc;\n\n#[tonic::async_trait]\nimpl test_server::Test for Svc {\n    async fn test_request(\n        self: Arc<Self>,\n        req: Request<SomeData>,\n    ) -> Result<Response<SomeData>, Status> {\n        Ok(Response::new(req.into_inner()))\n    }\n}\n\nfn main() {}\n"
  },
  {
    "path": "tests/compile/tests/ui.rs",
    "content": "#[test]\nfn ui() {\n    let t = trybuild::TestCases::new();\n    t.pass(\"tests/ui/*.rs\");\n}\n"
  },
  {
    "path": "tests/compression/Cargo.toml",
    "content": "[package]\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"compression\"\n\n[dependencies]\nbytes = \"1\"\nhttp = \"1\"\nhttp-body = \"1\"\nhttp-body-util = \"0.1\"\nhyper-util = \"0.1\"\npaste = \"1.0.12\"\npin-project = \"1.0\"\nprost = \"0.14\"\ntokio = {version = \"1.0\", features = [\"macros\", \"rt-multi-thread\", \"net\"]}\ntokio-stream = \"0.1\"\ntonic = {path = \"../../tonic\", features = [\"gzip\", \"deflate\", \"zstd\"]}\ntonic-prost = {path = \"../../tonic-prost\"}\ntower = \"0.5\"\ntower-http = {version = \"0.6\", features = [\"map-response-body\", \"map-request-body\"]}\n\n[build-dependencies]\ntonic-prost-build = {path = \"../../tonic-prost-build\" }\n"
  },
  {
    "path": "tests/compression/build.rs",
    "content": "fn main() {\n    tonic_prost_build::compile_protos(\"proto/test.proto\").unwrap();\n}\n"
  },
  {
    "path": "tests/compression/proto/test.proto",
    "content": "syntax = \"proto3\";\n\npackage test;\n\nimport \"google/protobuf/empty.proto\";\n\nservice Test {\n  rpc CompressOutputUnary(google.protobuf.Empty) returns (SomeData);\n  rpc CompressInputUnary(SomeData) returns (google.protobuf.Empty);\n  rpc CompressOutputServerStream(google.protobuf.Empty) returns (stream SomeData);\n  rpc CompressInputClientStream(stream SomeData) returns (google.protobuf.Empty);\n  rpc CompressOutputClientStream(stream SomeData) returns (SomeData);\n  rpc CompressInputOutputBidirectionalStream(stream SomeData) returns (stream SomeData);\n}\n\nmessage SomeData {\n  // include a bunch of data so there actually is something to compress\n  bytes data = 1;\n}\n"
  },
  {
    "path": "tests/compression/src/bidirectional_stream.rs",
    "content": "use super::*;\nuse http_body::Body;\nuse tonic::codec::CompressionEncoding;\n\nutil::parametrized_tests! {\n    client_enabled_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default())\n        .accept_compressed(encoding)\n        .send_compressed(encoding);\n\n    let request_bytes_counter = Arc::new(AtomicUsize::new(0));\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    #[derive(Clone)]\n    pub struct AssertRightEncoding {\n        encoding: CompressionEncoding,\n    }\n\n    #[allow(dead_code)]\n    impl AssertRightEncoding {\n        pub fn new(encoding: CompressionEncoding) -> Self {\n            Self { encoding }\n        }\n\n        pub fn call<B: Body>(self, req: http::Request<B>) -> http::Request<B> {\n            let expected = match self.encoding {\n                CompressionEncoding::Gzip => \"gzip\",\n                CompressionEncoding::Zstd => \"zstd\",\n                CompressionEncoding::Deflate => \"deflate\",\n                _ => panic!(\"unexpected encoding {:?}\", self.encoding),\n            };\n            assert_eq!(req.headers().get(\"grpc-encoding\").unwrap(), expected);\n\n            req\n        }\n    }\n\n    tokio::spawn({\n        let request_bytes_counter = request_bytes_counter.clone();\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .map_request(move |req| {\n                            AssertRightEncoding::new(encoding).clone().call(req)\n                        })\n                        .layer(measure_request_body_size_layer(\n                            request_bytes_counter.clone(),\n                        ))\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client = test_client::TestClient::new(mock_io_channel(client).await)\n        .send_compressed(encoding)\n        .accept_compressed(encoding);\n\n    let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec();\n    let stream = tokio_stream::iter(vec![SomeData { data: data.clone() }, SomeData { data }]);\n    let req = Request::new(stream);\n\n    let res = client\n        .compress_input_output_bidirectional_stream(req)\n        .await\n        .unwrap();\n\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n\n    let mut stream: Streaming<SomeData> = res.into_inner();\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n\n    assert!(request_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);\n    assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);\n}\n"
  },
  {
    "path": "tests/compression/src/client_stream.rs",
    "content": "use super::*;\nuse http_body::Body;\nuse tonic::codec::CompressionEncoding;\n\nutil::parametrized_tests! {\n    client_enabled_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding);\n\n    let request_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    #[derive(Clone)]\n    pub struct AssertRightEncoding {\n        encoding: CompressionEncoding,\n    }\n\n    #[allow(dead_code)]\n    impl AssertRightEncoding {\n        pub fn new(encoding: CompressionEncoding) -> Self {\n            Self { encoding }\n        }\n\n        pub fn call<B: Body>(self, req: http::Request<B>) -> http::Request<B> {\n            let expected = match self.encoding {\n                CompressionEncoding::Gzip => \"gzip\",\n                CompressionEncoding::Zstd => \"zstd\",\n                CompressionEncoding::Deflate => \"deflate\",\n                _ => panic!(\"unexpected encoding {:?}\", self.encoding),\n            };\n            assert_eq!(req.headers().get(\"grpc-encoding\").unwrap(), expected);\n\n            req\n        }\n    }\n\n    tokio::spawn({\n        let request_bytes_counter = request_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .map_request(move |req| {\n                            AssertRightEncoding::new(encoding).clone().call(req)\n                        })\n                        .layer(measure_request_body_size_layer(\n                            request_bytes_counter.clone(),\n                        ))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding);\n\n    let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec();\n    let stream = tokio_stream::iter(vec![SomeData { data: data.clone() }, SomeData { data }]);\n    let req = Request::new(Box::pin(stream));\n\n    client.compress_input_client_stream(req).await.unwrap();\n\n    let bytes_sent = request_bytes_counter.load(SeqCst);\n    assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    client_disabled_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_disabled_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding);\n\n    let request_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    fn assert_right_encoding<B>(req: http::Request<B>) -> http::Request<B> {\n        assert!(req.headers().get(\"grpc-encoding\").is_none());\n        req\n    }\n\n    tokio::spawn({\n        let request_bytes_counter = request_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .map_request(assert_right_encoding)\n                        .layer(measure_request_body_size_layer(\n                            request_bytes_counter.clone(),\n                        ))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client = test_client::TestClient::new(mock_io_channel(client).await);\n\n    let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec();\n    let stream = tokio_stream::iter(vec![SomeData { data: data.clone() }, SomeData { data }]);\n    let req = Request::new(Box::pin(stream));\n\n    client.compress_input_client_stream(req).await.unwrap();\n\n    let bytes_sent = request_bytes_counter.load(SeqCst);\n    assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    client_enabled_server_disabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_disabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default());\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n            .await\n            .unwrap();\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding);\n\n    let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec();\n    let stream = tokio_stream::iter(vec![SomeData { data: data.clone() }, SomeData { data }]);\n    let req = Request::new(Box::pin(stream));\n\n    let status = client.compress_input_client_stream(req).await.unwrap_err();\n\n    assert_eq!(status.code(), tonic::Code::Unimplemented);\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(\n        status.message(),\n        format!(\"Content is compressed with `{expected}` which isn't supported\")\n    );\n}\n\nutil::parametrized_tests! {\n    compressing_response_from_client_stream,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn compressing_response_from_client_stream(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let req = Request::new(Box::pin(tokio_stream::empty()));\n\n    let res = client.compress_output_client_stream(req).await.unwrap();\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n    let bytes_sent = response_bytes_counter.load(SeqCst);\n    assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE);\n}\n"
  },
  {
    "path": "tests/compression/src/compressing_request.rs",
    "content": "use super::*;\nuse http_body::Body;\nuse tonic::codec::CompressionEncoding;\n\nutil::parametrized_tests! {\n    client_enabled_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding);\n\n    let request_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    #[derive(Clone)]\n    pub struct AssertRightEncoding {\n        encoding: CompressionEncoding,\n    }\n\n    #[allow(dead_code)]\n    impl AssertRightEncoding {\n        pub fn new(encoding: CompressionEncoding) -> Self {\n            Self { encoding }\n        }\n\n        pub fn call<B: Body>(self, req: http::Request<B>) -> http::Request<B> {\n            let expected = match self.encoding {\n                CompressionEncoding::Gzip => \"gzip\",\n                CompressionEncoding::Zstd => \"zstd\",\n                CompressionEncoding::Deflate => \"deflate\",\n                _ => panic!(\"unexpected encoding {:?}\", self.encoding),\n            };\n            assert_eq!(req.headers().get(\"grpc-encoding\").unwrap(), expected);\n\n            req\n        }\n    }\n\n    tokio::spawn({\n        let request_bytes_counter = request_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(\n                            ServiceBuilder::new()\n                                .map_request(move |req| {\n                                    AssertRightEncoding::new(encoding).clone().call(req)\n                                })\n                                .layer(measure_request_body_size_layer(request_bytes_counter))\n                                .into_inner(),\n                        )\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)]))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding);\n\n    for _ in 0..3 {\n        client\n            .compress_input_unary(SomeData {\n                data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),\n            })\n            .await\n            .unwrap();\n        let bytes_sent = request_bytes_counter.load(SeqCst);\n        assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE);\n    }\n}\n\nutil::parametrized_tests! {\n    client_enabled_server_enabled_multi_encoding,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_enabled_multi_encoding(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default())\n        .accept_compressed(CompressionEncoding::Gzip)\n        .accept_compressed(CompressionEncoding::Zstd)\n        .accept_compressed(CompressionEncoding::Deflate);\n\n    let request_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    fn assert_right_encoding<B>(req: http::Request<B>) -> http::Request<B> {\n        let supported_encodings = [\"gzip\", \"zstd\", \"deflate\"];\n        let req_encoding = req.headers().get(\"grpc-encoding\").unwrap();\n        assert!(supported_encodings.iter().any(|e| e == req_encoding));\n\n        req\n    }\n\n    tokio::spawn({\n        let request_bytes_counter = request_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(\n                            ServiceBuilder::new()\n                                .map_request(assert_right_encoding)\n                                .layer(measure_request_body_size_layer(request_bytes_counter))\n                                .into_inner(),\n                        )\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding);\n\n    for _ in 0..3 {\n        client\n            .compress_input_unary(SomeData {\n                data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),\n            })\n            .await\n            .unwrap();\n        let bytes_sent = request_bytes_counter.load(SeqCst);\n        assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE);\n    }\n}\n\nparametrized_tests! {\n    client_enabled_server_disabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_disabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default());\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n            .await\n            .unwrap();\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding);\n\n    let status = client\n        .compress_input_unary(SomeData {\n            data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),\n        })\n        .await\n        .unwrap_err();\n\n    assert_eq!(status.code(), tonic::Code::Unimplemented);\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(\n        status.message(),\n        format!(\"Content is compressed with `{expected}` which isn't supported\")\n    );\n\n    assert_eq!(\n        status.metadata().get(\"grpc-accept-encoding\").unwrap(),\n        \"identity\"\n    );\n}\nparametrized_tests! {\n    client_mark_compressed_without_header_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_mark_compressed_without_header_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding);\n\n    tokio::spawn({\n        async move {\n            Server::builder()\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client = test_client::TestClient::with_interceptor(\n        mock_io_channel(client).await,\n        move |mut req: Request<()>| {\n            req.metadata_mut().remove(\"grpc-encoding\");\n            Ok(req)\n        },\n    )\n    .send_compressed(CompressionEncoding::Gzip);\n\n    let status = client\n        .compress_input_unary(SomeData {\n            data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),\n        })\n        .await\n        .unwrap_err();\n\n    assert_eq!(status.code(), tonic::Code::Internal);\n    assert_eq!(\n        status.message(),\n        \"protocol error: received message with compressed-flag but no grpc-encoding was specified\"\n    );\n}\n\nutil::parametrized_tests! {\n    limit_decoded_message_size,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[cfg(test)]\nasync fn limit_decoded_message_size(encoding: CompressionEncoding) {\n    use prost::Message;\n\n    let under_limit_request = SomeData {\n        data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),\n    };\n    let limit = under_limit_request.encoded_len();\n    let over_limit_request = SomeData {\n        data: [0_u8; 1 + UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),\n    };\n\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default())\n        .accept_compressed(encoding)\n        .max_decoding_message_size(limit);\n\n    let request_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let request_bytes_counter = request_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(\n                            ServiceBuilder::new()\n                                .layer(measure_request_body_size_layer(request_bytes_counter))\n                                .into_inner(),\n                        )\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding);\n\n    for _ in 0..3 {\n        // compressed messages that are under or exactly at the limit are successful.\n        client\n            .compress_input_unary(under_limit_request.clone())\n            .await\n            .unwrap();\n        let bytes_sent = request_bytes_counter.load(SeqCst);\n        assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE);\n\n        // compressed messages that are over the limit are fail with resource exhausted\n        let status = client\n            .compress_input_unary(over_limit_request.clone())\n            .await\n            .unwrap_err();\n        assert_eq!(status.code(), tonic::Code::ResourceExhausted);\n    }\n}\n"
  },
  {
    "path": "tests/compression/src/compressing_response.rs",
    "content": "use super::*;\nuse tonic::codec::CompressionEncoding;\n\nutil::parametrized_tests! {\n    client_enabled_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    #[derive(Clone, Copy)]\n    struct AssertCorrectAcceptEncoding<S> {\n        service: S,\n        encoding: CompressionEncoding,\n    }\n\n    impl<S, B> Service<http::Request<B>> for AssertCorrectAcceptEncoding<S>\n    where\n        S: Service<http::Request<B>>,\n    {\n        type Response = S::Response;\n        type Error = S::Error;\n        type Future = S::Future;\n\n        fn poll_ready(\n            &mut self,\n            cx: &mut std::task::Context<'_>,\n        ) -> std::task::Poll<Result<(), Self::Error>> {\n            self.service.poll_ready(cx)\n        }\n\n        fn call(&mut self, req: http::Request<B>) -> Self::Future {\n            let expected = match self.encoding {\n                CompressionEncoding::Gzip => \"gzip\",\n                CompressionEncoding::Zstd => \"zstd\",\n                CompressionEncoding::Deflate => \"deflate\",\n                _ => panic!(\"unexpected encoding {:?}\", self.encoding),\n            };\n            assert_eq!(\n                req.headers()\n                    .get(\"grpc-accept-encoding\")\n                    .unwrap()\n                    .to_str()\n                    .unwrap(),\n                format!(\"{expected},identity\")\n            );\n            self.service.call(req)\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(layer_fn(|service| AssertCorrectAcceptEncoding {\n                            service,\n                            encoding,\n                        }))\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n\n    for _ in 0..3 {\n        let res = client.compress_output_unary(()).await.unwrap();\n        assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n        let bytes_sent = response_bytes_counter.load(SeqCst);\n        assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE);\n    }\n}\n\nutil::parametrized_tests! {\n    client_enabled_server_disabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_disabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default());\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                // no compression enable on the server so responses should not be compressed\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)]))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let res = client.compress_output_unary(()).await.unwrap();\n\n    assert!(res.metadata().get(\"grpc-encoding\").is_none());\n\n    let bytes_sent = response_bytes_counter.load(SeqCst);\n    assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn client_enabled_server_disabled_multi_encoding() {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default());\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                // no compression enable on the server so responses should not be compressed\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client = test_client::TestClient::new(mock_io_channel(client).await)\n        .accept_compressed(CompressionEncoding::Gzip)\n        .accept_compressed(CompressionEncoding::Zstd)\n        .accept_compressed(CompressionEncoding::Deflate);\n\n    let res = client.compress_output_unary(()).await.unwrap();\n\n    assert!(res.metadata().get(\"grpc-encoding\").is_none());\n\n    let bytes_sent = response_bytes_counter.load(SeqCst);\n    assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    client_disabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_disabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    #[derive(Clone, Copy)]\n    struct AssertCorrectAcceptEncoding<S>(S);\n\n    impl<S, B> Service<http::Request<B>> for AssertCorrectAcceptEncoding<S>\n    where\n        S: Service<http::Request<B>>,\n    {\n        type Response = S::Response;\n        type Error = S::Error;\n        type Future = S::Future;\n\n        fn poll_ready(\n            &mut self,\n            cx: &mut std::task::Context<'_>,\n        ) -> std::task::Poll<Result<(), Self::Error>> {\n            self.0.poll_ready(cx)\n        }\n\n        fn call(&mut self, req: http::Request<B>) -> Self::Future {\n            assert!(req.headers().get(\"grpc-accept-encoding\").is_none());\n            self.0.call(req)\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(layer_fn(AssertCorrectAcceptEncoding))\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client = test_client::TestClient::new(mock_io_channel(client).await);\n\n    let res = client.compress_output_unary(()).await.unwrap();\n\n    assert!(res.metadata().get(\"grpc-encoding\").is_none());\n\n    let bytes_sent = response_bytes_counter.load(SeqCst);\n    assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    server_replying_with_unsupported_encoding,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn server_replying_with_unsupported_encoding(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding);\n\n    fn add_weird_content_encoding<B>(mut response: http::Response<B>) -> http::Response<B> {\n        response\n            .headers_mut()\n            .insert(\"grpc-encoding\", \"br\".parse().unwrap());\n        response\n    }\n\n    tokio::spawn(async move {\n        Server::builder()\n            .layer(\n                ServiceBuilder::new()\n                    .map_response(add_weird_content_encoding)\n                    .into_inner(),\n            )\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n            .await\n            .unwrap();\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n    let status: Status = client.compress_output_unary(()).await.unwrap_err();\n\n    assert_eq!(status.code(), tonic::Code::Unimplemented);\n    assert_eq!(\n        status.message(),\n        \"Content is compressed with `br` which isn't supported\"\n    );\n}\n\nutil::parametrized_tests! {\n    disabling_compression_on_single_response,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn disabling_compression_on_single_response(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc {\n        disable_compressing_on_response: true,\n    })\n    .send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let res = client.compress_output_unary(()).await.unwrap();\n\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n\n    let bytes_sent = response_bytes_counter.load(SeqCst);\n    assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    disabling_compression_on_response_but_keeping_compression_on_stream,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn disabling_compression_on_response_but_keeping_compression_on_stream(\n    encoding: CompressionEncoding,\n) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc {\n        disable_compressing_on_response: true,\n    })\n    .send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let res = client.compress_output_server_stream(()).await.unwrap();\n\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n\n    let mut stream: Streaming<SomeData> = res.into_inner();\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n    assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n    assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    disabling_compression_on_response_from_client_stream,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn disabling_compression_on_response_from_client_stream(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc {\n        disable_compressing_on_response: true,\n    })\n    .send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let req = Request::new(Box::pin(tokio_stream::empty()));\n\n    let res = client.compress_output_client_stream(req).await.unwrap();\n\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n    let bytes_sent = response_bytes_counter.load(SeqCst);\n    assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    limit_decoded_message_size,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[cfg(test)]\nasync fn limit_decoded_message_size(encoding: CompressionEncoding) {\n    use prost::Message;\n\n    let under_limit_request = SomeData {\n        data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),\n    };\n    let limit = under_limit_request.encoded_len();\n\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n\n    // compressed messages that are under or exactly at the limit are successful.\n    let mut under_limit_client = test_client::TestClient::new(mock_io_channel(client).await)\n        .accept_compressed(encoding)\n        .max_decoding_message_size(limit);\n\n    for _ in 0..3 {\n        let res = under_limit_client.compress_output_unary(()).await.unwrap();\n        assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n        let bytes_sent = response_bytes_counter.load(SeqCst);\n        assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE);\n    }\n\n    // compressed messages that are over the limit are fail with resource exhausted\n    let mut over_limit_client = under_limit_client.max_decoding_message_size(limit - 1);\n\n    for _ in 0..3 {\n        let status = over_limit_client\n            .compress_output_unary(())\n            .await\n            .unwrap_err();\n\n        assert_eq!(status.code(), tonic::Code::ResourceExhausted);\n    }\n}\n"
  },
  {
    "path": "tests/compression/src/lib.rs",
    "content": "#![allow(unused_imports)]\n\nuse self::util::*;\nuse crate::util::mock_io_channel;\nuse std::{\n    pin::Pin,\n    sync::{\n        atomic::{AtomicUsize, Ordering::SeqCst},\n        Arc,\n    },\n};\nuse tokio::net::TcpListener;\nuse tokio_stream::{Stream, StreamExt};\nuse tonic::{\n    transport::{Channel, Endpoint, Server, Uri},\n    Request, Response, Status, Streaming,\n};\nuse tower::{layer::layer_fn, service_fn, Service, ServiceBuilder};\nuse tower_http::{map_request_body::MapRequestBodyLayer, map_response_body::MapResponseBodyLayer};\n\nmod bidirectional_stream;\nmod client_stream;\nmod compressing_request;\nmod compressing_response;\nmod server_stream;\nmod util;\n\ntonic::include_proto!(\"test\");\n\n#[derive(Debug, Default)]\nstruct Svc {\n    disable_compressing_on_response: bool,\n}\n\nconst UNCOMPRESSED_MIN_BODY_SIZE: usize = 1024;\n\nimpl Svc {\n    fn prepare_response<B>(&self, mut res: Response<B>) -> Response<B> {\n        if self.disable_compressing_on_response {\n            res.disable_compression();\n        }\n\n        res\n    }\n}\n\n#[tonic::async_trait]\nimpl test_server::Test for Svc {\n    async fn compress_output_unary(&self, _req: Request<()>) -> Result<Response<SomeData>, Status> {\n        let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE];\n\n        Ok(self.prepare_response(Response::new(SomeData {\n            data: data.to_vec(),\n        })))\n    }\n\n    async fn compress_input_unary(&self, req: Request<SomeData>) -> Result<Response<()>, Status> {\n        assert_eq!(req.into_inner().data.len(), UNCOMPRESSED_MIN_BODY_SIZE);\n        Ok(Response::new(()))\n    }\n\n    type CompressOutputServerStreamStream =\n        Pin<Box<dyn Stream<Item = Result<SomeData, Status>> + Send + 'static>>;\n\n    async fn compress_output_server_stream(\n        &self,\n        _req: Request<()>,\n    ) -> Result<Response<Self::CompressOutputServerStreamStream>, Status> {\n        let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec();\n        let stream = tokio_stream::iter(std::iter::repeat(SomeData { data }))\n            .take(2)\n            .map(Ok::<_, Status>);\n        Ok(self.prepare_response(Response::new(Box::pin(stream))))\n    }\n\n    async fn compress_input_client_stream(\n        &self,\n        req: Request<Streaming<SomeData>>,\n    ) -> Result<Response<()>, Status> {\n        let mut stream = req.into_inner();\n        while let Some(item) = stream.next().await {\n            item.unwrap();\n        }\n        Ok(self.prepare_response(Response::new(())))\n    }\n\n    async fn compress_output_client_stream(\n        &self,\n        req: Request<Streaming<SomeData>>,\n    ) -> Result<Response<SomeData>, Status> {\n        let mut stream = req.into_inner();\n        while let Some(item) = stream.next().await {\n            item.unwrap();\n        }\n\n        let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE];\n\n        Ok(self.prepare_response(Response::new(SomeData {\n            data: data.to_vec(),\n        })))\n    }\n\n    type CompressInputOutputBidirectionalStreamStream =\n        Pin<Box<dyn Stream<Item = Result<SomeData, Status>> + Send + 'static>>;\n\n    async fn compress_input_output_bidirectional_stream(\n        &self,\n        req: Request<Streaming<SomeData>>,\n    ) -> Result<Response<Self::CompressInputOutputBidirectionalStreamStream>, Status> {\n        let mut stream = req.into_inner();\n        while let Some(item) = stream.next().await {\n            item.unwrap();\n        }\n\n        let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec();\n        let stream = tokio_stream::iter(std::iter::repeat(SomeData { data }))\n            .take(2)\n            .map(Ok::<_, Status>);\n        Ok(self.prepare_response(Response::new(Box::pin(stream))))\n    }\n}\n"
  },
  {
    "path": "tests/compression/src/server_stream.rs",
    "content": "use super::*;\nuse tonic::codec::CompressionEncoding;\nuse tonic::Streaming;\n\nutil::parametrized_tests! {\n    client_enabled_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let res = client.compress_output_server_stream(()).await.unwrap();\n\n    let expected = match encoding {\n        CompressionEncoding::Gzip => \"gzip\",\n        CompressionEncoding::Zstd => \"zstd\",\n        CompressionEncoding::Deflate => \"deflate\",\n        _ => panic!(\"unexpected encoding {encoding:?}\"),\n    };\n    assert_eq!(res.metadata().get(\"grpc-encoding\").unwrap(), expected);\n\n    let mut stream: Streaming<SomeData> = res.into_inner();\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n    assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n    assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    client_disabled_server_enabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n}\n\n#[allow(dead_code)]\nasync fn client_disabled_server_enabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding);\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client = test_client::TestClient::new(mock_io_channel(client).await);\n\n    let res = client.compress_output_server_stream(()).await.unwrap();\n\n    assert!(res.metadata().get(\"grpc-encoding\").is_none());\n\n    let mut stream: Streaming<SomeData> = res.into_inner();\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n    assert!(response_bytes_counter.load(SeqCst) > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n\nutil::parametrized_tests! {\n    client_enabled_server_disabled,\n    zstd: CompressionEncoding::Zstd,\n    gzip: CompressionEncoding::Gzip,\n    deflate: CompressionEncoding::Deflate,\n}\n\n#[allow(dead_code)]\nasync fn client_enabled_server_disabled(encoding: CompressionEncoding) {\n    let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);\n\n    let svc = test_server::TestServer::new(Svc::default());\n\n    let response_bytes_counter = Arc::new(AtomicUsize::new(0));\n\n    tokio::spawn({\n        let response_bytes_counter = response_bytes_counter.clone();\n        async move {\n            Server::builder()\n                .layer(\n                    ServiceBuilder::new()\n                        .layer(MapResponseBodyLayer::new(move |body| {\n                            util::CountBytesBody {\n                                inner: body,\n                                counter: response_bytes_counter.clone(),\n                            }\n                        }))\n                        .into_inner(),\n                )\n                .add_service(svc)\n                .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n                .await\n                .unwrap();\n        }\n    });\n\n    let mut client =\n        test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding);\n\n    let res = client.compress_output_server_stream(()).await.unwrap();\n\n    assert!(res.metadata().get(\"grpc-encoding\").is_none());\n\n    let mut stream: Streaming<SomeData> = res.into_inner();\n\n    stream\n        .next()\n        .await\n        .expect(\"stream empty\")\n        .expect(\"item was error\");\n    assert!(response_bytes_counter.load(SeqCst) > UNCOMPRESSED_MIN_BODY_SIZE);\n}\n"
  },
  {
    "path": "tests/compression/src/util.rs",
    "content": "use super::*;\nuse bytes::{Buf, Bytes};\nuse http_body::{Body as HttpBody, Frame};\nuse http_body_util::BodyExt as _;\nuse hyper_util::rt::TokioIo;\nuse pin_project::pin_project;\nuse std::{\n    pin::Pin,\n    sync::{\n        atomic::{AtomicUsize, Ordering::SeqCst},\n        Arc,\n    },\n    task::{ready, Context, Poll},\n};\nuse tokio::io::{AsyncRead, AsyncWrite, ReadBuf};\nuse tonic::body::Body;\nuse tonic::codec::CompressionEncoding;\nuse tonic::transport::{server::Connected, Channel};\nuse tower_http::map_request_body::MapRequestBodyLayer;\n\nmacro_rules! parametrized_tests {\n    ($fn_name:ident, $($test_name:ident: $input:expr),+ $(,)?) => {\n        paste::paste! {\n            $(\n                #[tokio::test(flavor = \"multi_thread\")]\n                async fn [<$fn_name _ $test_name>]() {\n                    let input = $input;\n                    $fn_name(input).await;\n                }\n            )+\n        }\n    }\n}\n\npub(crate) use parametrized_tests;\n\n/// A body that tracks how many bytes passes through it\n#[pin_project]\npub struct CountBytesBody<B> {\n    #[pin]\n    pub inner: B,\n    pub counter: Arc<AtomicUsize>,\n}\n\nimpl<B> HttpBody for CountBytesBody<B>\nwhere\n    B: HttpBody<Data = Bytes>,\n{\n    type Data = B::Data;\n    type Error = B::Error;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        let this = self.project();\n        let counter: Arc<AtomicUsize> = this.counter.clone();\n        match ready!(this.inner.poll_frame(cx)) {\n            Some(Ok(chunk)) => {\n                println!(\"response body chunk size = {}\", frame_data_length(&chunk));\n                counter.fetch_add(frame_data_length(&chunk), SeqCst);\n                Poll::Ready(Some(Ok(chunk)))\n            }\n            x => Poll::Ready(x),\n        }\n    }\n\n    fn is_end_stream(&self) -> bool {\n        self.inner.is_end_stream()\n    }\n\n    fn size_hint(&self) -> http_body::SizeHint {\n        self.inner.size_hint()\n    }\n}\n\nfn frame_data_length(frame: &http_body::Frame<Bytes>) -> usize {\n    if let Some(data) = frame.data_ref() {\n        data.len()\n    } else {\n        0\n    }\n}\n\n#[pin_project]\nstruct ChannelBody<T> {\n    #[pin]\n    rx: tokio::sync::mpsc::Receiver<Frame<T>>,\n}\n\nimpl<T> ChannelBody<T> {\n    pub fn new() -> (tokio::sync::mpsc::Sender<Frame<T>>, Self) {\n        let (tx, rx) = tokio::sync::mpsc::channel(32);\n        (tx, Self { rx })\n    }\n}\n\nimpl<T> HttpBody for ChannelBody<T>\nwhere\n    T: Buf,\n{\n    type Data = T;\n    type Error = tonic::Status;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        let frame = ready!(self.project().rx.poll_recv(cx));\n        Poll::Ready(frame.map(Ok))\n    }\n}\n\n#[allow(dead_code)]\npub fn measure_request_body_size_layer(\n    bytes_sent_counter: Arc<AtomicUsize>,\n) -> MapRequestBodyLayer<impl Fn(Body) -> Body + Clone> {\n    MapRequestBodyLayer::new(move |mut body: Body| {\n        let (tx, new_body) = ChannelBody::new();\n\n        let bytes_sent_counter = bytes_sent_counter.clone();\n        tokio::spawn(async move {\n            while let Some(chunk) = body.frame().await {\n                let chunk = chunk.unwrap();\n                println!(\"request body chunk size = {}\", frame_data_length(&chunk));\n                bytes_sent_counter.fetch_add(frame_data_length(&chunk), SeqCst);\n                tx.send(chunk).await.unwrap();\n            }\n        });\n\n        Body::new(new_body)\n    })\n}\n\n#[allow(dead_code)]\npub async fn mock_io_channel(client: tokio::io::DuplexStream) -> Channel {\n    let mut client = Some(client);\n\n    Endpoint::try_from(\"http://[::]:50051\")\n        .unwrap()\n        .connect_with_connector(service_fn(move |_: Uri| {\n            let client = TokioIo::new(client.take().unwrap());\n            async move { Ok::<_, std::io::Error>(client) }\n        }))\n        .await\n        .unwrap()\n}\n\n#[derive(Clone)]\npub struct AssertRightEncoding {\n    encoding: CompressionEncoding,\n}\n\n#[allow(dead_code)]\nimpl AssertRightEncoding {\n    pub fn new(encoding: CompressionEncoding) -> Self {\n        Self { encoding }\n    }\n\n    pub fn call<B: HttpBody>(self, req: http::Request<B>) -> http::Request<B> {\n        let expected = match self.encoding {\n            CompressionEncoding::Gzip => \"gzip\",\n            CompressionEncoding::Zstd => \"zstd\",\n            CompressionEncoding::Deflate => \"deflate\",\n            _ => panic!(\"unexpected encoding {:?}\", self.encoding),\n        };\n        assert_eq!(req.headers().get(\"grpc-encoding\").unwrap(), expected);\n\n        req\n    }\n}\n"
  },
  {
    "path": "tests/default_stubs/Cargo.toml",
    "content": "[package]\nauthors = [\"Jordan Singh <me@jordansingh.com>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"default_stubs\"\n\n[dependencies]\ntokio = {version = \"1.0\", features = [\"macros\", \"rt-multi-thread\", \"net\"]}\ntokio-stream = {version = \"0.1\", features = [\"net\"]}\ntonic = {path = \"../../tonic\"}\ntonic-prost = {path = \"../../tonic-prost\"}\n\n[dev-dependencies]\ntempfile = \"3.20\"\n\n[build-dependencies]\ntonic-prost-build = {path = \"../../tonic-prost-build\" }\n"
  },
  {
    "path": "tests/default_stubs/build.rs",
    "content": "fn main() {\n    tonic_prost_build::configure()\n        .compile_protos(&[\"proto/test.proto\"], &[\"proto\"])\n        .unwrap();\n    tonic_prost_build::configure()\n        .generate_default_stubs(true)\n        .compile_protos(&[\"proto/test_default.proto\"], &[\"proto\"])\n        .unwrap();\n}\n"
  },
  {
    "path": "tests/default_stubs/proto/test.proto",
    "content": "syntax = \"proto3\";\n\npackage test;\n\nimport \"google/protobuf/empty.proto\";\n\nservice Test {\n  rpc Unary(google.protobuf.Empty) returns (google.protobuf.Empty);\n  rpc ServerStream(google.protobuf.Empty) returns (stream google.protobuf.Empty);\n  rpc ClientStream(stream google.protobuf.Empty) returns (google.protobuf.Empty);\n  rpc BidirectionalStream(stream google.protobuf.Empty) returns (stream google.protobuf.Empty);\n}\n"
  },
  {
    "path": "tests/default_stubs/proto/test_default.proto",
    "content": "syntax = \"proto3\";\n\npackage test_default;\n\nimport \"google/protobuf/empty.proto\";\n\nservice TestDefault {\n  rpc Unary(google.protobuf.Empty) returns (google.protobuf.Empty);\n  rpc ServerStream(google.protobuf.Empty) returns (stream google.protobuf.Empty);\n  rpc ClientStream(stream google.protobuf.Empty) returns (google.protobuf.Empty);\n  rpc BidirectionalStream(stream google.protobuf.Empty) returns (stream google.protobuf.Empty);\n}\n"
  },
  {
    "path": "tests/default_stubs/src/lib.rs",
    "content": "use std::pin::Pin;\nuse tokio_stream::Stream;\nuse tonic::{Request, Response, Status, Streaming};\n\ntonic::include_proto!(\"test\");\ntonic::include_proto!(\"test_default\");\n\n#[derive(Debug, Default)]\npub struct Svc;\n\n#[tonic::async_trait]\nimpl test_server::Test for Svc {\n    type ServerStreamStream = Pin<Box<dyn Stream<Item = Result<(), Status>> + Send + 'static>>;\n    type BidirectionalStreamStream =\n        Pin<Box<dyn Stream<Item = Result<(), Status>> + Send + 'static>>;\n\n    async fn unary(&self, _: Request<()>) -> Result<Response<()>, Status> {\n        Err(Status::permission_denied(\"\"))\n    }\n\n    async fn server_stream(\n        &self,\n        _: Request<()>,\n    ) -> Result<Response<Self::ServerStreamStream>, Status> {\n        Err(Status::permission_denied(\"\"))\n    }\n\n    async fn client_stream(&self, _: Request<Streaming<()>>) -> Result<Response<()>, Status> {\n        Err(Status::permission_denied(\"\"))\n    }\n\n    async fn bidirectional_stream(\n        &self,\n        _: Request<Streaming<()>>,\n    ) -> Result<Response<Self::BidirectionalStreamStream>, Status> {\n        Err(Status::permission_denied(\"\"))\n    }\n}\n\n#[tonic::async_trait]\nimpl test_default_server::TestDefault for Svc {\n    // Default unimplemented stubs provided here.\n}\n"
  },
  {
    "path": "tests/default_stubs/tests/default.rs",
    "content": "use default_stubs::test_client::TestClient;\nuse default_stubs::*;\nuse std::net::SocketAddr;\nuse tokio::net::TcpListener;\nuse tokio_stream::{Stream, StreamExt};\nuse tonic::transport::Channel;\nuse tonic::transport::Server;\n\nfn echo_requests_iter() -> impl Stream<Item = ()> {\n    tokio_stream::iter(1..usize::MAX).map(|_| ())\n}\n\nasync fn test_default_stubs(\n    mut client: TestClient<Channel>,\n    mut client_default_stubs: TestClient<Channel>,\n) {\n    use tonic::Code;\n\n    // First validate pre-existing functionality (trait has no default implementation, we explicitly return PermissionDenied in lib.rs).\n    assert_eq!(\n        client.unary(()).await.unwrap_err().code(),\n        Code::PermissionDenied\n    );\n    assert_eq!(\n        client.server_stream(()).await.unwrap_err().code(),\n        Code::PermissionDenied\n    );\n    assert_eq!(\n        client\n            .client_stream(echo_requests_iter().take(5))\n            .await\n            .unwrap_err()\n            .code(),\n        Code::PermissionDenied\n    );\n    assert_eq!(\n        client\n            .bidirectional_stream(echo_requests_iter().take(5))\n            .await\n            .unwrap_err()\n            .code(),\n        Code::PermissionDenied\n    );\n\n    // Then validate opt-in new functionality (trait has default implementation of returning Unimplemented).\n    assert_eq!(\n        client_default_stubs.unary(()).await.unwrap_err().code(),\n        Code::Unimplemented\n    );\n    assert_eq!(\n        client_default_stubs\n            .server_stream(())\n            .await\n            .unwrap_err()\n            .code(),\n        Code::Unimplemented\n    );\n    assert_eq!(\n        client_default_stubs\n            .client_stream(echo_requests_iter().take(5))\n            .await\n            .unwrap_err()\n            .code(),\n        Code::Unimplemented\n    );\n    assert_eq!(\n        client_default_stubs\n            .bidirectional_stream(echo_requests_iter().take(5))\n            .await\n            .unwrap_err()\n            .code(),\n        Code::Unimplemented\n    );\n}\n\n#[tokio::test()]\nasync fn test_default_stubs_tcp() {\n    let addrs = run_services_in_background().await;\n    let client = test_client::TestClient::connect(format!(\"http://{}\", addrs.0))\n        .await\n        .unwrap();\n    let client_default_stubs = test_client::TestClient::connect(format!(\"http://{}\", addrs.1))\n        .await\n        .unwrap();\n    test_default_stubs(client, client_default_stubs).await;\n}\n\n#[tokio::test()]\n#[cfg(not(target_os = \"windows\"))]\nasync fn test_default_stubs_uds() {\n    let addrs = run_services_in_background_uds().await;\n    let client = test_client::TestClient::connect(addrs.0).await.unwrap();\n    let client_default_stubs = test_client::TestClient::connect(addrs.1).await.unwrap();\n    test_default_stubs(client, client_default_stubs).await;\n}\n\nasync fn run_services_in_background() -> (SocketAddr, SocketAddr) {\n    let svc = test_server::TestServer::new(Svc {});\n    let svc_default_stubs = test_default_server::TestDefaultServer::new(Svc {});\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n\n    let listener_default_stubs = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr_default_stubs = listener_default_stubs.local_addr().unwrap();\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))\n            .await\n            .unwrap();\n    });\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc_default_stubs)\n            .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(\n                listener_default_stubs,\n            ))\n            .await\n            .unwrap();\n    });\n\n    (addr, addr_default_stubs)\n}\n\n#[cfg(not(target_os = \"windows\"))]\nasync fn run_services_in_background_uds() -> (String, String) {\n    use tokio::net::UnixListener;\n\n    let svc = test_server::TestServer::new(Svc {});\n    let svc_default_stubs = test_default_server::TestDefaultServer::new(Svc {});\n\n    let tmpdir = tempfile::Builder::new()\n        .prefix(\"tonic-test-\")\n        .tempdir()\n        .unwrap()\n        .keep();\n\n    let uds_filepath = tmpdir.join(\"impl.sock\").to_str().unwrap().to_string();\n    let listener = UnixListener::bind(uds_filepath.as_str()).unwrap();\n    let uds_addr = format!(\"unix://{uds_filepath}\");\n\n    let uds_default_stubs_filepath = tmpdir.join(\"stub.sock\").to_str().unwrap().to_string();\n    let listener_default_stubs = UnixListener::bind(uds_default_stubs_filepath.as_str()).unwrap();\n    let uds_default_stubs_addr = format!(\"unix://{uds_default_stubs_filepath}\");\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::wrappers::UnixListenerStream::new(listener))\n            .await\n            .unwrap();\n    });\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc_default_stubs)\n            .serve_with_incoming(tokio_stream::wrappers::UnixListenerStream::new(\n                listener_default_stubs,\n            ))\n            .await\n            .unwrap();\n    });\n\n    (uds_addr, uds_default_stubs_addr)\n}\n"
  },
  {
    "path": "tests/deprecated_methods/Cargo.toml",
    "content": "[package]\nname = \"deprecated_methods\"\nedition = \"2021\"\nlicense = \"MIT\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nprost = \"0.14\"\ntonic = { path = \"../../tonic\" }\ntonic-prost = { path = \"../../tonic-prost\" }\n\n[build-dependencies]\ntonic-prost-build = { path = \"../../tonic-prost-build\" }\n"
  },
  {
    "path": "tests/deprecated_methods/build.rs",
    "content": "fn main() {\n    tonic_prost_build::compile_protos(\"proto/test.proto\").unwrap();\n}\n"
  },
  {
    "path": "tests/deprecated_methods/proto/test.proto",
    "content": "syntax = \"proto3\";\n\npackage test;\n\nservice Service1 {\n  rpc Deprecated(Request) returns (Response) {\n    option deprecated = true;\n  }\n  rpc NotDeprecated(Request) returns (Response);\n}\n\nmessage Request {}\n\nmessage Response {}\n"
  },
  {
    "path": "tests/deprecated_methods/src/lib.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"test\");\n}\n"
  },
  {
    "path": "tests/deprecated_methods/tests/deprecated_methods.rs",
    "content": "use std::{fs, path::PathBuf};\n\n#[test]\nfn test() {\n    let path = PathBuf::from(std::env::var(\"OUT_DIR\").unwrap()).join(\"test.rs\");\n    let s = fs::read_to_string(path)\n        .unwrap()\n        .split_whitespace()\n        .collect::<Vec<_>>()\n        .join(\" \");\n    assert!(s.contains(\"#[deprecated] pub async fn deprecated(\"));\n    assert!(!s.contains(\"#[deprecated] pub async fn not_deprecated(\"));\n}\n"
  },
  {
    "path": "tests/disable_comments/Cargo.toml",
    "content": "[package]\nauthors = [\"bouzuya <m@bouzuya.net>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"disable-comments\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nprost = \"0.14\"\ntonic = { path = \"../../tonic\" }\ntonic-prost = { path = \"../../tonic-prost\" }\n\n[build-dependencies]\ntonic-prost-build = { path = \"../../tonic-prost-build\" }\n"
  },
  {
    "path": "tests/disable_comments/build.rs",
    "content": "fn main() {\n    let mut config = tonic_prost_build::Config::default();\n    config.disable_comments([\"test.Input1\", \"test.Output1\"]);\n    tonic_prost_build::configure()\n        .disable_comments([\"test.Service1\"])\n        .disable_comments([\"test.Service1.Rpc1\"])\n        .build_client(true)\n        .build_server(true)\n        .compile_with_config(config, &[\"proto/test.proto\"], &[\"proto\"])\n        .unwrap();\n}\n"
  },
  {
    "path": "tests/disable_comments/proto/test.proto",
    "content": "syntax = \"proto3\";\n\npackage test;\n\n// This comment will be removed.\nservice Service1 {\n  // This comment will be removed.\n  rpc Rpc1(Input1) returns (Output1);\n  // This comment will not be removed.\n  rpc Rpc2(Input2) returns (Output2);\n}\n\n// This comment will not be removed.\nservice Service2 {\n  // This comment will not be removed.\n  rpc Rpc(Input1) returns (Output1);\n}\n\n// This comment will be removed.\nmessage Input1 {}\n\n// This comment will not be removed.\nmessage Input2 {}\n\n// This comment will be removed.\nmessage Output1 {}\n\n// This comment will not be removed.\nmessage Output2 {}\n"
  },
  {
    "path": "tests/disable_comments/src/lib.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"test\");\n}\n"
  },
  {
    "path": "tests/disable_comments/tests/disable_comments.rs",
    "content": "use std::{fs, path::PathBuf};\n\n#[test]\nfn test() {\n    let path = PathBuf::from(std::env::var(\"OUT_DIR\").unwrap()).join(\"test.rs\");\n    let s = fs::read_to_string(path).unwrap();\n    assert!(!s.contains(\"This comment will be removed.\"));\n    let mut count = 0_usize;\n    let mut index = 0_usize;\n    while let Some(found) = s[index..].find(\"This comment will not be removed.\") {\n        index += found + 1;\n        count += 1;\n    }\n    assert_eq!(count, 2 + 3 + 3); // message: 2, client: 3, server: 3\n}\n"
  },
  {
    "path": "tests/extern_path/my_application/Cargo.toml",
    "content": "[package]\nauthors = [\"Danny Hua <danny@42layers.io>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"my_application\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nprost = \"0.14\"\ntonic = {path = \"../../../tonic\"}\ntonic-prost = {path = \"../../../tonic-prost\"}\nuuid = {package = \"uuid1\", path = \"../uuid\"}\n\n[build-dependencies]\ntonic-prost-build = {path = \"../../../tonic-prost-build\"}\n"
  },
  {
    "path": "tests/extern_path/my_application/build.rs",
    "content": "fn main() -> Result<(), std::io::Error> {\n    tonic_prost_build::configure()\n        .build_server(false)\n        .build_client(true)\n        .extern_path(\".uuid\", \"::uuid\")\n        .compile_protos(\n            &[\"service.proto\", \"uuid.proto\"],\n            &[\"../proto/my_application\", \"../proto/uuid\"],\n        )?;\n    Ok(())\n}\n"
  },
  {
    "path": "tests/extern_path/my_application/src/main.rs",
    "content": "use uuid::DoSomething;\nmod pb {\n    tonic::include_proto!(\"my_application\");\n}\nfn main() {\n    // verify that extern_path to replace proto's with impl's from other crates works.\n    let message = pb::MyMessage {\n        message_id: Some(::uuid::Uuid {\n            uuid_str: \"\".to_string(),\n        }),\n        some_payload: \"\".to_string(),\n    };\n    dbg!(message.message_id.unwrap().do_it());\n}\n#[cfg(test)]\n#[test]\nfn service_types_have_extern_types() {\n    // verify that extern_path to replace proto's with impl's from other crates works.\n    let message = pb::MyMessage {\n        message_id: Some(::uuid::Uuid {\n            uuid_str: \"not really a uuid\".to_string(),\n        }),\n        some_payload: \"payload\".to_string(),\n    };\n    assert_eq!(message.message_id.unwrap().do_it(), \"Done\");\n}\n"
  },
  {
    "path": "tests/extern_path/proto/my_application/service.proto",
    "content": "syntax = \"proto3\";\n\npackage my_application;\n\noption go_package = \"my_applicationpb\";\noption java_multiple_files = true;\noption java_outer_classname = \"ServiceProto\";\noption java_package = \"com.my_application\";\n\n\nimport \"uuid.proto\";\n\nmessage MyMessage {\n    uuid.Uuid message_id = 1;\n    string some_payload = 2;\n}\n\nservice MyService {\n    rpc GetUuid(MyMessage) returns (uuid.Uuid){\n\n    }\n    rpc GetMyMessage(uuid.Uuid) returns (MyMessage){\n\n    }\n}\n"
  },
  {
    "path": "tests/extern_path/proto/uuid/uuid.proto",
    "content": "syntax = \"proto3\";\n\npackage uuid;\n\noption go_package = \"uuidpb\";\noption java_multiple_files = true;\noption java_outer_classname = \"UuidProto\";\noption java_package = \"com.uuid\";\n\n\nmessage Uuid {\n    string uuid_str = 1;\n}\n"
  },
  {
    "path": "tests/extern_path/uuid/Cargo.toml",
    "content": "[package]\nauthors = [\"Danny Hua <danny@42layers.io>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"uuid1\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nprost = \"0.14\"\n[build-dependencies]\nprost-build = \"0.14\"\n"
  },
  {
    "path": "tests/extern_path/uuid/build.rs",
    "content": "fn main() {\n    prost_build::compile_protos(&[\"uuid/uuid.proto\"], &[\"../proto/\"]).unwrap();\n}\n"
  },
  {
    "path": "tests/extern_path/uuid/src/lib.rs",
    "content": "include!(concat!(env!(\"OUT_DIR\"), \"/uuid.rs\"));\n\npub trait DoSomething {\n    fn do_it(&self) -> String;\n}\n\nimpl DoSomething for Uuid {\n    fn do_it(&self) -> String {\n        \"Done\".to_string()\n    }\n}\n"
  },
  {
    "path": "tests/integration_tests/Cargo.toml",
    "content": "[package]\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"integration-tests\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nbytes = \"1.0\"\nprost = \"0.14\"\ntokio = {version = \"1.0\", features = [\"macros\", \"rt-multi-thread\", \"net\", \"sync\"]}\ntonic = {path = \"../../tonic\"}\ntonic-prost = {path = \"../../tonic-prost\"}\ntracing-subscriber = {version = \"0.3\"}\n\n[dev-dependencies]\nhttp = \"1\"\nhttp-body = \"1\"\nhyper-util = \"0.1\"\nrustls = {version = \"0.23\", features = [\"ring\"]}\ntokio-stream = {version = \"0.1.5\", features = [\"net\"]}\ntower = \"0.5\"\ntower-http = { version = \"0.6\", features = [\"set-header\", \"trace\"] }\ntower-service = \"0.3\"\n\n[build-dependencies]\ntonic-prost-build = {path = \"../../tonic-prost-build\"}\n"
  },
  {
    "path": "tests/integration_tests/build.rs",
    "content": "fn main() {\n    tonic_prost_build::compile_protos(\"proto/test.proto\").unwrap();\n    tonic_prost_build::compile_protos(\"proto/stream.proto\").unwrap();\n}\n"
  },
  {
    "path": "tests/integration_tests/proto/stream.proto",
    "content": "syntax = \"proto3\";\n\npackage stream;\n\nservice TestStream {\n  rpc StreamCall(InputStream) returns (stream OutputStream);\n}\n\nmessage InputStream {}\nmessage OutputStream {}\n"
  },
  {
    "path": "tests/integration_tests/proto/test.proto",
    "content": "syntax = \"proto3\";\n\npackage test;\n\nservice Test {\n  rpc UnaryCall(Input) returns (Output);\n}\n\nmessage Input {}\nmessage Output {}\n\nservice Test1 {\n  rpc UnaryCall(Input1) returns (Output1);\n\n  rpc StreamCall(Input1) returns (stream Output1);\n}\n\nmessage Input1 {\n  bytes buf = 1;\n}\nmessage Output1 {\n  bytes buf = 1;\n}\n"
  },
  {
    "path": "tests/integration_tests/src/lib.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"test\");\n    tonic::include_proto!(\"stream\");\n}\n\npub mod mock {\n    use std::{\n        io::IoSlice,\n        pin::Pin,\n        task::{Context, Poll},\n    };\n\n    use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};\n    use tonic::transport::server::Connected;\n\n    #[derive(Debug)]\n    pub struct MockStream(pub tokio::io::DuplexStream);\n\n    impl Connected for MockStream {\n        type ConnectInfo = ();\n\n        /// Create type holding information about the connection.\n        fn connect_info(&self) -> Self::ConnectInfo {}\n    }\n\n    impl AsyncRead for MockStream {\n        fn poll_read(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            buf: &mut ReadBuf<'_>,\n        ) -> Poll<std::io::Result<()>> {\n            Pin::new(&mut self.0).poll_read(cx, buf)\n        }\n    }\n\n    impl AsyncWrite for MockStream {\n        fn poll_write(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            buf: &[u8],\n        ) -> Poll<std::io::Result<usize>> {\n            Pin::new(&mut self.0).poll_write(cx, buf)\n        }\n\n        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n            Pin::new(&mut self.0).poll_flush(cx)\n        }\n\n        fn poll_shutdown(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n        ) -> Poll<std::io::Result<()>> {\n            Pin::new(&mut self.0).poll_shutdown(cx)\n        }\n\n        fn poll_write_vectored(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            bufs: &[IoSlice<'_>],\n        ) -> Poll<Result<usize, std::io::Error>> {\n            Pin::new(&mut self.0).poll_write_vectored(cx, bufs)\n        }\n\n        fn is_write_vectored(&self) -> bool {\n            self.0.is_write_vectored()\n        }\n    }\n}\n\npub fn trace_init() {\n    let _ = tracing_subscriber::fmt::try_init();\n}\n\npub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;\n"
  },
  {
    "path": "tests/integration_tests/tests/client_layer.rs",
    "content": "use http::{header::HeaderName, HeaderValue};\nuse integration_tests::pb::{test_client::TestClient, test_server, Input, Output};\nuse std::time::Duration;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::{\n    transport::{server::TcpIncoming, Endpoint, Server},\n    Request, Response, Status,\n};\nuse tower::ServiceBuilder;\nuse tower_http::{set_header::SetRequestHeaderLayer, trace::TraceLayer};\n\n#[tokio::test]\nasync fn connect_supports_standard_tower_layers() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n            match req.metadata().get(\"x-test\") {\n                Some(_) => Ok(Response::new(Output {})),\n                None => Err(Status::internal(\"user-agent header is missing\")),\n            }\n        }\n    }\n\n    let (tx, rx) = oneshot::channel();\n    let svc = test_server::TestServer::new(Svc);\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    // Start the server now, second call should succeed\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .connect_lazy();\n\n    // prior to https://github.com/hyperium/tonic/pull/974\n    // this would not compile. (specifically the `TraceLayer`)\n    let mut client = TestClient::new(\n        ServiceBuilder::new()\n            .layer(SetRequestHeaderLayer::overriding(\n                HeaderName::from_static(\"x-test\"),\n                HeaderValue::from_static(\"test-header\"),\n            ))\n            .layer(TraceLayer::new_for_grpc())\n            .service(channel),\n    );\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n    client.unary_call(Request::new(Input {})).await.unwrap();\n\n    tx.send(()).unwrap();\n    jh.await.unwrap();\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/complex_tower_middleware.rs",
    "content": "#![allow(unused_variables, dead_code)]\n\nuse http_body::Body;\nuse integration_tests::pb::{test_server, Input, Output};\nuse std::{\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tonic::{transport::Server, Request, Response, Status};\nuse tower::{layer::Layer, BoxError, Service};\n\n// all we care about is that this compiles\nasync fn complex_tower_layers_work() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n            unimplemented!()\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    Server::builder()\n        .layer(MyServiceLayer::new())\n        .add_service(svc)\n        .serve(\"127.0.0.1:0\".parse().unwrap())\n        .await\n        .unwrap();\n}\n\n#[derive(Debug, Clone)]\nstruct MyServiceLayer {}\n\nimpl MyServiceLayer {\n    fn new() -> Self {\n        unimplemented!()\n    }\n}\n\nimpl<S> Layer<S> for MyServiceLayer {\n    type Service = MyService<S>;\n\n    fn layer(&self, inner: S) -> Self::Service {\n        unimplemented!()\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct MyService<S> {\n    inner: S,\n}\n\nimpl<S, R, ResBody> Service<R> for MyService<S>\nwhere\n    S: Service<R, Response = http::Response<ResBody>>,\n{\n    type Response = http::Response<MyBody<ResBody>>;\n    type Error = BoxError;\n    type Future = MyFuture<S::Future, ResBody>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        unimplemented!()\n    }\n\n    fn call(&mut self, req: R) -> Self::Future {\n        unimplemented!()\n    }\n}\n\nstruct MyFuture<F, B> {\n    inner: F,\n    body: B,\n}\n\nimpl<F, E, B> Future for MyFuture<F, B>\nwhere\n    F: Future<Output = Result<http::Response<B>, E>>,\n{\n    type Output = Result<http::Response<MyBody<B>>, BoxError>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        unimplemented!()\n    }\n}\n\nstruct MyBody<B> {\n    inner: B,\n}\n\nimpl<B> Body for MyBody<B>\nwhere\n    B: Body,\n{\n    type Data = B::Data;\n    type Error = BoxError;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {\n        unimplemented!()\n    }\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/connect_info.rs",
    "content": "use integration_tests::pb::{test_client, test_server, Input, Output};\nuse std::time::Duration;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::{\n    transport::{\n        server::{TcpConnectInfo, TcpIncoming},\n        Endpoint, Server,\n    },\n    Request, Response, Status,\n};\n\n#[tokio::test]\nasync fn getting_connect_info() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n            assert!(req.local_addr().is_some());\n            assert!(req.remote_addr().is_some());\n            assert!(req.extensions().get::<TcpConnectInfo>().is_some());\n\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client = test_client::TestClient::new(channel);\n\n    client.unary_call(Input {}).await.unwrap();\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n\n#[cfg(unix)]\npub mod unix {\n    use std::io;\n\n    use hyper_util::rt::TokioIo;\n    use tokio::{\n        net::{UnixListener, UnixStream},\n        sync::oneshot,\n    };\n    use tokio_stream::wrappers::UnixListenerStream;\n    use tonic::{\n        transport::{server::UdsConnectInfo, Endpoint, Server, Uri},\n        Request, Response, Status,\n    };\n    use tower::service_fn;\n\n    use integration_tests::pb::{test_client, test_server, Input, Output};\n\n    struct Svc {}\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n            let conn_info = req.extensions().get::<UdsConnectInfo>().unwrap();\n\n            // Client-side unix sockets are unnamed.\n            assert!(req.local_addr().is_none());\n            assert!(req.remote_addr().is_none());\n            assert!(conn_info.peer_addr.as_ref().unwrap().is_unnamed());\n            // This should contain process credentials for the client socket.\n            assert!(conn_info.peer_cred.as_ref().is_some());\n\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    #[tokio::test]\n    async fn getting_connect_info() {\n        let mut unix_socket_path = std::env::temp_dir();\n        unix_socket_path.push(\"uds-integration-test\");\n\n        let uds = UnixListener::bind(&unix_socket_path).unwrap();\n        let uds_stream = UnixListenerStream::new(uds);\n\n        let service = test_server::TestServer::new(Svc {});\n        let (tx, rx) = oneshot::channel::<()>();\n\n        let jh = tokio::spawn(async move {\n            Server::builder()\n                .add_service(service)\n                .serve_with_incoming_shutdown(uds_stream, async { drop(rx.await) })\n                .await\n                .unwrap();\n        });\n\n        // Take a copy before moving into the `service_fn` closure so that the closure\n        // can implement `FnMut`.\n        let path = unix_socket_path.clone();\n        let channel = Endpoint::try_from(\"http://[::]:50051\")\n            .unwrap()\n            .connect_with_connector(service_fn(move |_: Uri| {\n                let path = path.clone();\n                async move { Ok::<_, io::Error>(TokioIo::new(UnixStream::connect(path).await?)) }\n            }))\n            .await\n            .unwrap();\n\n        let mut client = test_client::TestClient::new(channel);\n\n        client.unary_call(Input {}).await.unwrap();\n\n        tx.send(()).unwrap();\n        jh.await.unwrap();\n\n        std::fs::remove_file(unix_socket_path).unwrap();\n    }\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/connection.rs",
    "content": "use integration_tests::pb::{test_client::TestClient, test_server, Input, Output};\nuse std::sync::{Arc, Mutex};\nuse std::time::Duration;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::{\n    transport::{server::TcpIncoming, Endpoint, Server},\n    Code, Request, Response, Status,\n};\n\nstruct Svc(Arc<Mutex<Option<oneshot::Sender<()>>>>);\n\n#[tonic::async_trait]\nimpl test_server::Test for Svc {\n    async fn unary_call(&self, _: Request<Input>) -> Result<Response<Output>, Status> {\n        let mut l = self.0.lock().unwrap();\n        l.take().unwrap().send(()).unwrap();\n\n        Ok(Response::new(Output {}))\n    }\n}\n\n#[tokio::test]\nasync fn connect_returns_err() {\n    let res = TestClient::connect(\"http://thisdoesntexist.test\").await;\n\n    assert!(res.is_err());\n}\n\n#[tokio::test]\nasync fn connect_handles_tls() {\n    rustls::crypto::ring::default_provider()\n        .install_default()\n        .unwrap();\n    TestClient::connect(\"https://github.com\").await.unwrap();\n}\n\n#[tokio::test]\nasync fn connect_returns_err_via_call_after_connected() {\n    let (tx, rx) = oneshot::channel();\n    let sender = Arc::new(Mutex::new(Some(tx)));\n    let svc = test_server::TestServer::new(Svc(sender));\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let mut client = TestClient::connect(format!(\"http://{addr}\")).await.unwrap();\n\n    // First call should pass, then shutdown the server\n    client.unary_call(Request::new(Input {})).await.unwrap();\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let res = client.unary_call(Request::new(Input {})).await;\n\n    let err = res.unwrap_err();\n    assert_eq!(err.code(), Code::Unavailable);\n\n    jh.await.unwrap();\n}\n\n#[tokio::test]\nasync fn connect_lazy_reconnects_after_first_failure() {\n    let (tx, rx) = oneshot::channel();\n    let sender = Arc::new(Mutex::new(Some(tx)));\n    let svc = test_server::TestServer::new(Svc(sender));\n\n    {\n        let channel = Endpoint::from_static(\"http://127.0.0.1:0\").connect_lazy();\n        let mut client = TestClient::new(channel);\n\n        // First call should fail, the server is not running\n        client.unary_call(Request::new(Input {})).await.unwrap_err();\n    }\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    // Start the server now, second call should succeed\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .connect_lazy();\n\n    let mut client = TestClient::new(channel);\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n    client.unary_call(Request::new(Input {})).await.unwrap();\n\n    // The server shut down, third call should fail\n    tokio::time::sleep(Duration::from_millis(100)).await;\n    let err = client.unary_call(Request::new(Input {})).await.unwrap_err();\n\n    assert_eq!(err.code(), Code::Unavailable);\n\n    jh.await.unwrap();\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/extensions.rs",
    "content": "use integration_tests::{\n    pb::{test_client, test_server, Input, Output},\n    BoxFuture,\n};\nuse std::{\n    task::{Context, Poll},\n    time::Duration,\n};\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::{\n    body::Body,\n    server::NamedService,\n    transport::{server::TcpIncoming, Endpoint, Server},\n    Request, Response, Status,\n};\nuse tower_service::Service;\n\n#[derive(Clone)]\nstruct ExtensionValue(i32);\n\n#[tokio::test]\nasync fn setting_extension_from_interceptor() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n            let value = req.extensions().get::<ExtensionValue>().unwrap();\n            assert_eq!(value.0, 42);\n\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    let svc = test_server::TestServer::with_interceptor(Svc, |mut req: Request<()>| {\n        req.extensions_mut().insert(ExtensionValue(42));\n        Ok(req)\n    });\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client = test_client::TestClient::new(channel);\n\n    client.unary_call(Input {}).await.unwrap();\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n\n#[tokio::test]\nasync fn setting_extension_from_tower() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n            let value = req.extensions().get::<ExtensionValue>().unwrap();\n            assert_eq!(value.0, 42);\n\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    let svc = InterceptedService {\n        inner: test_server::TestServer::new(Svc),\n    };\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client = test_client::TestClient::new(channel);\n\n    client.unary_call(Input {}).await.unwrap();\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n\n#[derive(Debug, Clone)]\nstruct InterceptedService<S> {\n    inner: S,\n}\n\nimpl<S> Service<http::Request<Body>> for InterceptedService<S>\nwhere\n    S: Service<http::Request<Body>, Response = http::Response<Body>>\n        + NamedService\n        + Clone\n        + Send\n        + 'static,\n    S::Future: Send + 'static,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, mut req: http::Request<Body>) -> Self::Future {\n        let clone = self.inner.clone();\n        let mut inner = std::mem::replace(&mut self.inner, clone);\n\n        req.extensions_mut().insert(ExtensionValue(42));\n\n        Box::pin(async move {\n            let response = inner.call(req).await?;\n            Ok(response)\n        })\n    }\n}\n\nimpl<S: NamedService> NamedService for InterceptedService<S> {\n    const NAME: &'static str = S::NAME;\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/http2_keep_alive.rs",
    "content": "use std::time::Duration;\n\nuse tokio::{net::TcpListener, sync::oneshot};\n\nuse integration_tests::pb::{test_client::TestClient, test_server, Input, Output};\nuse tonic::transport::{server::TcpIncoming, Channel, Server};\nuse tonic::{Request, Response, Status};\n\nstruct Svc;\n\n#[tonic::async_trait]\nimpl test_server::Test for Svc {\n    async fn unary_call(&self, _: Request<Input>) -> Result<Response<Output>, Status> {\n        Ok(Response::new(Output {}))\n    }\n}\n\n#[tokio::test]\nasync fn http2_keepalive_does_not_cause_panics() {\n    let svc = test_server::TestServer::new(Svc {});\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .http2_keepalive_interval(Some(Duration::from_secs(10)))\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let mut client = TestClient::connect(format!(\"http://{addr}\")).await.unwrap();\n\n    let res = client.unary_call(Request::new(Input {})).await;\n\n    assert!(res.is_ok());\n\n    tx.send(()).unwrap();\n    jh.await.unwrap();\n}\n\n#[tokio::test]\nasync fn http2_keepalive_does_not_cause_panics_on_client_side() {\n    let svc = test_server::TestServer::new(Svc {});\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .http2_keepalive_interval(Some(Duration::from_secs(5)))\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Channel::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .http2_keep_alive_interval(Duration::from_secs(5))\n        .connect()\n        .await\n        .unwrap();\n    let mut client = TestClient::new(channel);\n\n    let res = client.unary_call(Request::new(Input {})).await;\n\n    assert!(res.is_ok());\n\n    tx.send(()).unwrap();\n    jh.await.unwrap();\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/http2_max_header_list_size.rs",
    "content": "use std::time::Duration;\n\nuse integration_tests::pb::{test_client, test_server, Input, Output};\nuse tokio::sync::oneshot;\nuse tonic::{\n    transport::{Endpoint, Server},\n    Request, Response, Status,\n};\n\n/// This test checks that the max header list size is respected, and that\n/// it allows for error messages up to that size.\n#[tokio::test]\nasync fn test_http_max_header_list_size_and_long_errors() {\n    struct Svc;\n\n    // The default value is 16k.\n    const N: usize = 20_000;\n\n    fn long_message() -> String {\n        \"a\".repeat(N)\n    }\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, _: Request<Input>) -> Result<Response<Output>, Status> {\n            Err(Status::internal(long_message()))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel::<()>();\n    let listener = tokio::net::TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = format!(\"http://{}\", listener.local_addr().unwrap());\n\n    let jh = tokio::spawn(async move {\n        let (nodelay, keepalive) = (Some(true), Some(Duration::from_secs(1)));\n        let listener = tonic::transport::server::TcpIncoming::from(listener)\n            .with_nodelay(nodelay)\n            .with_keepalive(keepalive);\n        Server::builder()\n            .http2_max_pending_accept_reset_streams(Some(0))\n            .add_service(svc)\n            .serve_with_incoming_shutdown(listener, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Endpoint::from_shared(addr)\n        .unwrap()\n        // Increase the max header list size to 2x the default value. If this is\n        // not set, this test will hang. See\n        // <https://github.com/hyperium/tonic/issues/1834>.\n        .http2_max_header_list_size(u32::try_from(N * 2).unwrap())\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client = test_client::TestClient::new(channel);\n\n    let err = client.unary_call(Request::new(Input {})).await.unwrap_err();\n\n    assert_eq!(err.message(), long_message());\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/interceptor.rs",
    "content": "use integration_tests::pb::{test_client::TestClient, test_server, Input, Output};\nuse std::time::Duration;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::{\n    transport::{server::TcpIncoming, Endpoint, Server},\n    GrpcMethod, Request, Response, Status,\n};\n\n#[tokio::test]\nasync fn interceptor_retrieves_grpc_method() {\n    use test_server::Test;\n\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl Test for Svc {\n        async fn unary_call(&self, _: Request<Input>) -> Result<Response<Output>, Status> {\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    // Start the server now, second call should succeed\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .connect_lazy();\n\n    fn client_intercept(req: Request<()>) -> Result<Request<()>, Status> {\n        println!(\"Intercepting client request: {req:?}\");\n\n        let gm = req.extensions().get::<GrpcMethod>().unwrap();\n        assert_eq!(gm.service(), \"test.Test\");\n        assert_eq!(gm.method(), \"UnaryCall\");\n\n        Ok(req)\n    }\n    let mut client = TestClient::with_interceptor(channel, client_intercept);\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n    client.unary_call(Request::new(Input {})).await.unwrap();\n\n    tx.send(()).unwrap();\n    jh.await.unwrap();\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/load_shed.rs",
    "content": "use integration_tests::pb::{test_client, test_server, Input, Output};\nuse std::net::SocketAddr;\nuse tokio::net::TcpListener;\nuse tonic::{transport::Server, Code, Request, Response, Status};\n\n#[tokio::test]\nasync fn service_resource_exhausted() {\n    let addr = run_service_in_background(0).await;\n\n    let mut client = test_client::TestClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let req = Request::new(Input {});\n    let res = client.unary_call(req).await;\n\n    let err = res.unwrap_err();\n    assert_eq!(err.code(), Code::ResourceExhausted);\n}\n\n#[tokio::test]\nasync fn service_resource_not_exhausted() {\n    let addr = run_service_in_background(1).await;\n\n    let mut client = test_client::TestClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let req = Request::new(Input {});\n    let res = client.unary_call(req).await;\n\n    assert!(res.is_ok());\n}\n\nasync fn run_service_in_background(concurrency_limit: usize) -> SocketAddr {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, _req: Request<Input>) -> Result<Response<Output>, Status> {\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc {});\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n\n    tokio::spawn(async move {\n        Server::builder()\n            .concurrency_limit_per_connection(concurrency_limit)\n            .load_shed(true)\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))\n            .await\n            .unwrap();\n    });\n\n    addr\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/max_message_size.rs",
    "content": "use std::pin::Pin;\n\nuse hyper_util::rt::TokioIo;\nuse integration_tests::{\n    pb::{test1_client, test1_server, Input1, Output1},\n    trace_init,\n};\nuse tokio_stream::Stream;\nuse tonic::{\n    transport::{Endpoint, Server},\n    Code, Request, Response, Status,\n};\n\n#[test]\nfn max_message_recv_size() {\n    trace_init();\n\n    // Server recv\n    assert_server_recv_max_success(128);\n    // 5 is the size of the gRPC header\n    assert_server_recv_max_success((4 * 1024 * 1024) - 5);\n    // 4mb is the max recv size\n    assert_server_recv_max_failure(4 * 1024 * 1024);\n    assert_server_recv_max_failure(4 * 1024 * 1024 + 1);\n    assert_server_recv_max_failure(8 * 1024 * 1024);\n\n    // Client recv\n    assert_client_recv_max_success(128);\n    // 5 is the size of the gRPC header\n    assert_client_recv_max_success((4 * 1024 * 1024) - 5);\n    // 4mb is the max recv size\n    assert_client_recv_max_failure(4 * 1024 * 1024);\n    assert_client_recv_max_failure(4 * 1024 * 1024 + 1);\n    assert_client_recv_max_failure(8 * 1024 * 1024);\n\n    // Custom limit settings\n    assert_test_case(TestCase {\n        // 5 is the size of the gRPC header\n        server_blob_size: 1024 - 5,\n        client_recv_max: Some(1024),\n        ..Default::default()\n    });\n    assert_test_case(TestCase {\n        server_blob_size: 1024,\n        client_recv_max: Some(1024),\n        expected_code: Some(Code::OutOfRange),\n        ..Default::default()\n    });\n\n    assert_test_case(TestCase {\n        // 5 is the size of the gRPC header\n        client_blob_size: 1024 - 5,\n        server_recv_max: Some(1024),\n        ..Default::default()\n    });\n    assert_test_case(TestCase {\n        client_blob_size: 1024,\n        server_recv_max: Some(1024),\n        expected_code: Some(Code::OutOfRange),\n        ..Default::default()\n    });\n}\n\n#[test]\nfn max_message_send_size() {\n    trace_init();\n\n    // Check client send limit works\n    assert_test_case(TestCase {\n        client_blob_size: 4 * 1024 * 1024,\n        server_recv_max: Some(usize::MAX),\n        ..Default::default()\n    });\n    assert_test_case(TestCase {\n        // 5 is the size of the gRPC header\n        client_blob_size: 1024 - 5,\n        server_recv_max: Some(usize::MAX),\n        client_send_max: Some(1024),\n        ..Default::default()\n    });\n    assert_test_case(TestCase {\n        // 5 is the size of the gRPC header\n        client_blob_size: 4 * 1024 * 1024,\n        server_recv_max: Some(usize::MAX),\n        // Set client send limit to 1024\n        client_send_max: Some(1024),\n        // TODO: This should return OutOfRange\n        // https://github.com/hyperium/tonic/issues/1334\n        expected_code: Some(Code::Internal),\n        ..Default::default()\n    });\n\n    // Check server send limit works\n    assert_test_case(TestCase {\n        server_blob_size: 4 * 1024 * 1024,\n        client_recv_max: Some(usize::MAX),\n        ..Default::default()\n    });\n    assert_test_case(TestCase {\n        // 5 is the gRPC header size\n        server_blob_size: 1024 - 5,\n        client_recv_max: Some(usize::MAX),\n        // Set server send limit to 1024\n        server_send_max: Some(1024),\n        ..Default::default()\n    });\n    assert_test_case(TestCase {\n        server_blob_size: 4 * 1024 * 1024,\n        client_recv_max: Some(usize::MAX),\n        // Set server send limit to 1024\n        server_send_max: Some(1024),\n        expected_code: Some(Code::OutOfRange),\n        ..Default::default()\n    });\n}\n\n#[tokio::test]\nasync fn response_stream_limit() {\n    let client_blob = vec![0; 1];\n\n    let (client, server) = tokio::io::duplex(1024);\n\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test1_server::Test1 for Svc {\n        async fn unary_call(&self, _req: Request<Input1>) -> Result<Response<Output1>, Status> {\n            unimplemented!()\n        }\n\n        type StreamCallStream =\n            Pin<Box<dyn Stream<Item = Result<Output1, Status>> + Send + 'static>>;\n\n        async fn stream_call(\n            &self,\n            _req: Request<Input1>,\n        ) -> Result<Response<Self::StreamCallStream>, Status> {\n            let blob = Output1 {\n                buf: vec![0; 6877902],\n            };\n            let stream = tokio_stream::iter(vec![Ok(blob.clone()), Ok(blob.clone())]);\n\n            Ok(Response::new(Box::pin(stream)))\n        }\n    }\n\n    let svc = test1_server::Test1Server::new(Svc);\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n            .await\n            .unwrap();\n    });\n\n    // Move client to an option so we can _move_ the inner value\n    // on the first attempt to connect. All other attempts will fail.\n    let mut client = Some(client);\n    let channel = Endpoint::try_from(\"http://[::]:50051\")\n        .unwrap()\n        .connect_with_connector(tower::service_fn(move |_| {\n            let client = client.take();\n\n            async move {\n                if let Some(client) = client {\n                    Ok(TokioIo::new(client))\n                } else {\n                    Err(std::io::Error::other(\"Client already taken\"))\n                }\n            }\n        }))\n        .await\n        .unwrap();\n\n    let client = test1_client::Test1Client::new(channel);\n\n    let mut client = client.max_decoding_message_size(6877902 + 5);\n\n    let req = Request::new(Input1 {\n        buf: client_blob.clone(),\n    });\n\n    let mut stream = client.stream_call(req).await.unwrap().into_inner();\n\n    while let Some(_b) = stream.message().await.unwrap() {}\n}\n\n// Track caller doesn't work on async fn so we extract the async part\n// into a sync version and assert the response there using track track_caller\n// so that when this does panic it tells us which line in the test failed not\n// where we placed the panic call.\n\n#[track_caller]\nfn assert_server_recv_max_success(size: usize) {\n    let case = TestCase {\n        client_blob_size: size,\n        server_blob_size: 0,\n        ..Default::default()\n    };\n\n    assert_test_case(case);\n}\n\n#[track_caller]\nfn assert_server_recv_max_failure(size: usize) {\n    let case = TestCase {\n        client_blob_size: size,\n        server_blob_size: 0,\n        expected_code: Some(Code::OutOfRange),\n        ..Default::default()\n    };\n\n    assert_test_case(case);\n}\n\n#[track_caller]\nfn assert_client_recv_max_success(size: usize) {\n    let case = TestCase {\n        client_blob_size: 0,\n        server_blob_size: size,\n        ..Default::default()\n    };\n\n    assert_test_case(case);\n}\n\n#[track_caller]\nfn assert_client_recv_max_failure(size: usize) {\n    let case = TestCase {\n        client_blob_size: 0,\n        server_blob_size: size,\n        expected_code: Some(Code::OutOfRange),\n        ..Default::default()\n    };\n\n    assert_test_case(case);\n}\n\n#[track_caller]\nfn assert_test_case(case: TestCase) {\n    let res = max_message_run(&case);\n\n    match (case.expected_code, res) {\n        (Some(_), Ok(())) => panic!(\"Expected failure, but got success\"),\n        (Some(code), Err(status)) => {\n            if status.code() != code {\n                panic!(\"Expected failure, got failure but wrong code, got: {status:?}\")\n            }\n        }\n\n        (None, Err(status)) => panic!(\"Expected success, but got failure, got: {status:?}\"),\n\n        _ => (),\n    }\n}\n\n#[derive(Default)]\nstruct TestCase {\n    client_blob_size: usize,\n    server_blob_size: usize,\n    client_recv_max: Option<usize>,\n    server_recv_max: Option<usize>,\n    client_send_max: Option<usize>,\n    server_send_max: Option<usize>,\n\n    expected_code: Option<Code>,\n}\n\n#[tokio::main]\nasync fn max_message_run(case: &TestCase) -> Result<(), Status> {\n    let client_blob = vec![0; case.client_blob_size];\n    let server_blob = vec![0; case.server_blob_size];\n\n    let (client, server) = tokio::io::duplex(1024);\n\n    struct Svc(Vec<u8>);\n\n    #[tonic::async_trait]\n    impl test1_server::Test1 for Svc {\n        async fn unary_call(&self, _req: Request<Input1>) -> Result<Response<Output1>, Status> {\n            Ok(Response::new(Output1 {\n                buf: self.0.clone(),\n            }))\n        }\n\n        type StreamCallStream =\n            Pin<Box<dyn Stream<Item = Result<Output1, Status>> + Send + 'static>>;\n\n        async fn stream_call(\n            &self,\n            _req: Request<Input1>,\n        ) -> Result<Response<Self::StreamCallStream>, Status> {\n            unimplemented!()\n        }\n    }\n\n    let svc = test1_server::Test1Server::new(Svc(server_blob));\n\n    let svc = if let Some(size) = case.server_recv_max {\n        svc.max_decoding_message_size(size)\n    } else {\n        svc\n    };\n\n    let svc = if let Some(size) = case.server_send_max {\n        svc.max_encoding_message_size(size)\n    } else {\n        svc\n    };\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server)))\n            .await\n            .unwrap();\n    });\n\n    // Move client to an option so we can _move_ the inner value\n    // on the first attempt to connect. All other attempts will fail.\n    let mut client = Some(client);\n    let channel = Endpoint::try_from(\"http://[::]:50051\")\n        .unwrap()\n        .connect_with_connector(tower::service_fn(move |_| {\n            let client = client.take();\n\n            async move {\n                if let Some(client) = client {\n                    Ok(TokioIo::new(client))\n                } else {\n                    Err(std::io::Error::other(\"Client already taken\"))\n                }\n            }\n        }))\n        .await\n        .unwrap();\n\n    let client = test1_client::Test1Client::new(channel);\n\n    let client = if let Some(size) = case.client_recv_max {\n        client.max_decoding_message_size(size)\n    } else {\n        client\n    };\n\n    let mut client = if let Some(size) = case.client_send_max {\n        client.max_encoding_message_size(size)\n    } else {\n        client\n    };\n\n    let req = Request::new(Input1 {\n        buf: client_blob.clone(),\n    });\n\n    client.unary_call(req).await.map(|_| ())\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/origin.rs",
    "content": "use integration_tests::pb::test_client;\nuse integration_tests::pb::{test_server, Input, Output};\nuse integration_tests::BoxFuture;\nuse std::task::Context;\nuse std::task::Poll;\nuse std::time::Duration;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::codegen::http::Request;\nuse tonic::{\n    transport::{server::TcpIncoming, Endpoint, Server},\n    Response, Status,\n};\nuse tower::Layer;\nuse tower::Service;\n\n#[tokio::test]\nasync fn writes_origin_header() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(\n            &self,\n            _req: tonic::Request<Input>,\n        ) -> Result<Response<Output>, Status> {\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .layer(OriginLayer {})\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .origin(\"https://docs.rs\".parse().expect(\"valid uri\"))\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client = test_client::TestClient::new(channel);\n\n    match client.unary_call(Input {}).await {\n        Ok(_) => {}\n        Err(status) => panic!(\"{}\", status.message()),\n    }\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n\n#[derive(Clone)]\nstruct OriginLayer {}\n\nimpl<S> Layer<S> for OriginLayer {\n    type Service = OriginService<S>;\n\n    fn layer(&self, inner: S) -> Self::Service {\n        OriginService { inner }\n    }\n}\n\n#[derive(Clone)]\nstruct OriginService<S> {\n    inner: S,\n}\n\nimpl<T> Service<Request<tonic::body::Body>> for OriginService<T>\nwhere\n    T: Service<Request<tonic::body::Body>>,\n    T::Future: Send + 'static,\n    T::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n{\n    type Response = T::Response;\n    type Error = Box<dyn std::error::Error + Send + Sync>;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: Request<tonic::body::Body>) -> Self::Future {\n        assert_eq!(req.uri().host(), Some(\"docs.rs\"));\n        let fut = self.inner.call(req);\n\n        Box::pin(async move { fut.await.map_err(Into::into) })\n    }\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/routes_builder.rs",
    "content": "use std::time::Duration;\n\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tokio_stream::StreamExt;\n\nuse integration_tests::pb::{\n    test1_client, test1_server, test_client, test_server, Input, Input1, Output, Output1,\n};\nuse tonic::codegen::BoxStream;\nuse tonic::service::RoutesBuilder;\nuse tonic::transport::server::TcpIncoming;\nuse tonic::{\n    transport::{Endpoint, Server},\n    Request, Response, Status,\n};\n\n#[tokio::test]\nasync fn multiple_service_using_routes_builder() {\n    struct Svc1;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc1 {\n        async fn unary_call(&self, _req: Request<Input>) -> Result<Response<Output>, Status> {\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    struct Svc2;\n\n    #[tonic::async_trait]\n    impl test1_server::Test1 for Svc2 {\n        async fn unary_call(&self, request: Request<Input1>) -> Result<Response<Output1>, Status> {\n            Ok(Response::new(Output1 {\n                buf: request.into_inner().buf,\n            }))\n        }\n\n        type StreamCallStream = BoxStream<Output1>;\n\n        async fn stream_call(\n            &self,\n            request: Request<Input1>,\n        ) -> Result<Response<Self::StreamCallStream>, Status> {\n            let output = Output1 {\n                buf: request.into_inner().buf,\n            };\n            let stream = tokio_stream::once(Ok(output));\n\n            Ok(Response::new(Box::pin(stream)))\n        }\n    }\n\n    let svc1 = test_server::TestServer::new(Svc1);\n    let svc2 = test1_server::Test1Server::new(Svc2);\n\n    let (tx, rx) = oneshot::channel::<()>();\n    let mut routes_builder = RoutesBuilder::default();\n    routes_builder.add_service(svc1).add_service(svc2);\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_routes(routes_builder.routes())\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client1 = test_client::TestClient::new(channel.clone());\n    let mut client2 = test1_client::Test1Client::new(channel);\n\n    client1.unary_call(Input {}).await.unwrap();\n\n    let resp2 = client2\n        .unary_call(Input1 {\n            buf: b\"hello\".to_vec(),\n        })\n        .await\n        .unwrap()\n        .into_inner();\n    assert_eq!(&resp2.buf, b\"hello\");\n    let mut stream_response = client2\n        .stream_call(Input1 {\n            buf: b\"world\".to_vec(),\n        })\n        .await\n        .unwrap()\n        .into_inner();\n    let first = match stream_response.next().await {\n        Some(Ok(first)) => first,\n        _ => panic!(\"expected one non-error item in the stream call response\"),\n    };\n\n    assert_eq!(&first.buf, b\"world\");\n    assert!(stream_response.next().await.is_none());\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/status.rs",
    "content": "use bytes::Bytes;\nuse http::Uri;\nuse hyper_util::rt::TokioIo;\nuse integration_tests::mock::MockStream;\nuse integration_tests::pb::{\n    test_client, test_server, test_stream_client, test_stream_server, Input, InputStream, Output,\n    OutputStream,\n};\nuse integration_tests::BoxFuture;\nuse std::error::Error;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::body::Body;\nuse tonic::metadata::{MetadataMap, MetadataValue};\nuse tonic::{\n    transport::{server::TcpIncoming, Endpoint, Server},\n    Code, Request, Response, Status,\n};\n\n#[tokio::test]\nasync fn status_with_details() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, _: Request<Input>) -> Result<Response<Output>, Status> {\n            Err(Status::with_details(\n                Code::ResourceExhausted,\n                \"Too many requests\",\n                Bytes::from_static(&[1]),\n            ))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let mut channel = test_client::TestClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let err = channel\n        .unary_call(Request::new(Input {}))\n        .await\n        .unwrap_err();\n\n    assert_eq!(err.message(), \"Too many requests\");\n    assert_eq!(err.details(), &[1]);\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n\n#[tokio::test]\nasync fn status_with_metadata() {\n    const MESSAGE: &str = \"Internal error, see metadata for details\";\n\n    const ASCII_NAME: &str = \"x-host-ip\";\n    const ASCII_VALUE: &str = \"127.0.0.1\";\n\n    const BINARY_NAME: &str = \"x-host-name-bin\";\n    const BINARY_VALUE: &[u8] = b\"localhost\";\n\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, _: Request<Input>) -> Result<Response<Output>, Status> {\n            let mut metadata = MetadataMap::new();\n            metadata.insert(ASCII_NAME, ASCII_VALUE.parse().unwrap());\n            metadata.insert_bin(BINARY_NAME, MetadataValue::from_bytes(BINARY_VALUE));\n\n            Err(Status::with_metadata(Code::Internal, MESSAGE, metadata))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let mut channel = test_client::TestClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let err = channel\n        .unary_call(Request::new(Input {}))\n        .await\n        .unwrap_err();\n\n    assert_eq!(err.code(), Code::Internal);\n    assert_eq!(err.message(), MESSAGE);\n\n    let metadata = err.metadata();\n\n    assert_eq!(\n        metadata.get(ASCII_NAME).unwrap().to_str().unwrap(),\n        ASCII_VALUE\n    );\n\n    assert_eq!(\n        metadata.get_bin(BINARY_NAME).unwrap().to_bytes().unwrap(),\n        BINARY_VALUE\n    );\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n\ntype Stream<T> = std::pin::Pin<\n    Box<dyn tokio_stream::Stream<Item = std::result::Result<T, Status>> + Send + 'static>,\n>;\n\n#[tokio::test]\nasync fn status_from_server_stream() {\n    integration_tests::trace_init();\n\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_stream_server::TestStream for Svc {\n        type StreamCallStream = Stream<OutputStream>;\n\n        async fn stream_call(\n            &self,\n            _: Request<InputStream>,\n        ) -> Result<Response<Self::StreamCallStream>, Status> {\n            let s = tokio_stream::iter(vec![\n                Err::<OutputStream, _>(Status::unavailable(\"foo\")),\n                Err::<OutputStream, _>(Status::unavailable(\"bar\")),\n            ]);\n            Ok(Response::new(Box::pin(s) as Self::StreamCallStream))\n        }\n    }\n\n    let svc = test_stream_server::TestStreamServer::new(Svc);\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(incoming)\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let mut client = test_stream_client::TestStreamClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let mut stream = client\n        .stream_call(InputStream {})\n        .await\n        .unwrap()\n        .into_inner();\n\n    assert_eq!(stream.message().await.unwrap_err().message(), \"foo\");\n    assert_eq!(stream.message().await.unwrap(), None);\n}\n\n#[tokio::test]\nasync fn status_from_server_stream_with_source() {\n    integration_tests::trace_init();\n\n    let channel = Endpoint::try_from(\"http://[::]:50051\")\n        .unwrap()\n        .connect_with_connector_lazy(tower::service_fn(move |_: Uri| async move {\n            Err::<TokioIo<MockStream>, _>(std::io::Error::other(\"WTF\"))\n        }));\n\n    let mut client = test_stream_client::TestStreamClient::new(channel);\n\n    let error = client.stream_call(InputStream {}).await.unwrap_err();\n\n    let source = error.source().unwrap();\n    source.downcast_ref::<tonic::transport::Error>().unwrap();\n}\n\n#[tokio::test]\nasync fn status_from_server_stream_with_inferred_status() {\n    integration_tests::trace_init();\n\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_stream_server::TestStream for Svc {\n        type StreamCallStream = Stream<OutputStream>;\n\n        async fn stream_call(\n            &self,\n            _: Request<InputStream>,\n        ) -> Result<Response<Self::StreamCallStream>, Status> {\n            let s = tokio_stream::once(Ok(OutputStream {}));\n            Ok(Response::new(Box::pin(s) as Self::StreamCallStream))\n        }\n    }\n\n    #[derive(Clone)]\n    struct TestLayer;\n\n    impl<S> tower::Layer<S> for TestLayer {\n        type Service = TestService;\n\n        fn layer(&self, _: S) -> Self::Service {\n            TestService\n        }\n    }\n\n    #[derive(Clone)]\n    struct TestService;\n\n    impl tower::Service<http::Request<Body>> for TestService {\n        type Response = http::Response<Body>;\n        type Error = std::convert::Infallible;\n        type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n        fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n\n        fn call(&mut self, _: http::Request<Body>) -> Self::Future {\n            Box::pin(async {\n                Ok(http::Response::builder()\n                    .status(http::StatusCode::BAD_GATEWAY)\n                    .body(Body::empty())\n                    .unwrap())\n            })\n        }\n    }\n\n    let svc = test_stream_server::TestStreamServer::new(Svc);\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming: TcpIncoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    tokio::spawn(async move {\n        Server::builder()\n            .layer(TestLayer)\n            .add_service(svc)\n            .serve_with_incoming(incoming)\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let mut client = test_stream_client::TestStreamClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let mut stream = client\n        .stream_call(InputStream {})\n        .await\n        .unwrap()\n        .into_inner();\n\n    assert_eq!(\n        stream.message().await.unwrap_err().code(),\n        Code::Unavailable\n    );\n\n    assert_eq!(stream.message().await.unwrap(), None);\n}\n\n#[tokio::test]\nasync fn message_and_then_status_from_server_stream() {\n    integration_tests::trace_init();\n\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_stream_server::TestStream for Svc {\n        type StreamCallStream = Stream<OutputStream>;\n\n        async fn stream_call(\n            &self,\n            _: Request<InputStream>,\n        ) -> Result<Response<Self::StreamCallStream>, Status> {\n            let s = tokio_stream::iter(vec![\n                Ok(OutputStream {}),\n                Err::<OutputStream, _>(Status::unavailable(\"foo\")),\n            ]);\n            Ok(Response::new(Box::pin(s) as Self::StreamCallStream))\n        }\n    }\n\n    let svc = test_stream_server::TestStreamServer::new(Svc);\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming(incoming)\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let mut client = test_stream_client::TestStreamClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let mut stream = client\n        .stream_call(InputStream {})\n        .await\n        .unwrap()\n        .into_inner();\n\n    assert_eq!(stream.message().await.unwrap(), Some(OutputStream {}));\n    assert_eq!(stream.message().await.unwrap_err().message(), \"foo\");\n    assert_eq!(stream.message().await.unwrap(), None);\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/streams.rs",
    "content": "use integration_tests::pb::{test_stream_server, InputStream, OutputStream};\nuse tokio::sync::oneshot;\nuse tonic::{transport::Server, Request, Response, Status};\n\ntype Stream<T> = std::pin::Pin<\n    Box<dyn tokio_stream::Stream<Item = std::result::Result<T, Status>> + Send + 'static>,\n>;\n\n#[tokio::test]\nasync fn status_from_server_stream_with_source() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_stream_server::TestStream for Svc {\n        type StreamCallStream = Stream<OutputStream>;\n\n        async fn stream_call(\n            &self,\n            _: Request<InputStream>,\n        ) -> Result<Response<Self::StreamCallStream>, Status> {\n            let s = Unsync(std::ptr::null_mut::<()>());\n\n            Ok(Response::new(Box::pin(s) as Self::StreamCallStream))\n        }\n    }\n\n    let svc = test_stream_server::TestStreamServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_shutdown(\"127.0.0.1:0\".parse().unwrap(), async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n\n#[allow(dead_code)]\nstruct Unsync(*mut ());\n\nunsafe impl Send for Unsync {}\n\nimpl tokio_stream::Stream for Unsync {\n    type Item = Result<OutputStream, Status>;\n\n    fn poll_next(\n        self: std::pin::Pin<&mut Self>,\n        _cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Option<Self::Item>> {\n        unimplemented!()\n    }\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/timeout.rs",
    "content": "use integration_tests::pb::{test_client, test_server, Input, Output};\nuse std::{net::SocketAddr, time::Duration};\nuse tokio::net::TcpListener;\nuse tonic::{transport::Server, Code, Request, Response, Status};\n\n#[tokio::test]\nasync fn cancelation_on_timeout() {\n    let addr = run_service_in_background(Duration::from_secs(1), Duration::from_secs(100)).await;\n\n    let mut client = test_client::TestClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let mut req = Request::new(Input {});\n    req.metadata_mut()\n        // 500 ms\n        .insert(\"grpc-timeout\", \"500m\".parse().unwrap());\n\n    let res = client.unary_call(req).await;\n\n    let err = res.unwrap_err();\n    assert!(err.message().contains(\"Timeout expired\"));\n    assert_eq!(err.code(), Code::Cancelled);\n}\n\n#[tokio::test]\nasync fn picks_server_timeout_if_thats_sorter() {\n    let addr = run_service_in_background(Duration::from_secs(1), Duration::from_millis(100)).await;\n\n    let mut client = test_client::TestClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let mut req = Request::new(Input {});\n    req.metadata_mut()\n        // 10 hours\n        .insert(\"grpc-timeout\", \"10H\".parse().unwrap());\n\n    let res = client.unary_call(req).await;\n    let err = res.unwrap_err();\n    assert!(err.message().contains(\"Timeout expired\"));\n    assert_eq!(err.code(), Code::Cancelled);\n}\n\n#[tokio::test]\nasync fn picks_client_timeout_if_thats_sorter() {\n    let addr = run_service_in_background(Duration::from_secs(1), Duration::from_secs(100)).await;\n\n    let mut client = test_client::TestClient::connect(format!(\"http://{addr}\"))\n        .await\n        .unwrap();\n\n    let mut req = Request::new(Input {});\n    req.metadata_mut()\n        // 100 ms\n        .insert(\"grpc-timeout\", \"100m\".parse().unwrap());\n\n    let res = client.unary_call(req).await;\n    let err = res.unwrap_err();\n    assert!(err.message().contains(\"Timeout expired\"));\n    assert_eq!(err.code(), Code::Cancelled);\n}\n\nasync fn run_service_in_background(latency: Duration, server_timeout: Duration) -> SocketAddr {\n    struct Svc {\n        latency: Duration,\n    }\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, _req: Request<Input>) -> Result<Response<Output>, Status> {\n            tokio::time::sleep(self.latency).await;\n            Ok(Response::new(Output {}))\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc { latency });\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n\n    tokio::spawn(async move {\n        Server::builder()\n            .timeout(server_timeout)\n            .add_service(svc)\n            .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))\n            .await\n            .unwrap();\n    });\n\n    addr\n}\n"
  },
  {
    "path": "tests/integration_tests/tests/user_agent.rs",
    "content": "use integration_tests::pb::{test_client, test_server, Input, Output};\nuse std::time::Duration;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::{\n    transport::{server::TcpIncoming, Endpoint, Server},\n    Request, Response, Status,\n};\n\n#[tokio::test]\nasync fn writes_user_agent_header() {\n    struct Svc;\n\n    #[tonic::async_trait]\n    impl test_server::Test for Svc {\n        async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n            match req.metadata().get(\"user-agent\") {\n                Some(_) => Ok(Response::new(Output {})),\n                None => Err(Status::internal(\"user-agent header is missing\")),\n            }\n        }\n    }\n\n    let svc = test_server::TestServer::new(Svc);\n\n    let (tx, rx) = oneshot::channel::<()>();\n\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n    let addr = listener.local_addr().unwrap();\n    let incoming = TcpIncoming::from(listener).with_nodelay(Some(true));\n\n    let jh = tokio::spawn(async move {\n        Server::builder()\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async { drop(rx.await) })\n            .await\n            .unwrap();\n    });\n\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let channel = Endpoint::from_shared(format!(\"http://{addr}\"))\n        .unwrap()\n        .user_agent(\"my-client\")\n        .expect(\"valid user agent\")\n        .connect()\n        .await\n        .unwrap();\n\n    let mut client = test_client::TestClient::new(channel);\n\n    match client.unary_call(Input {}).await {\n        Ok(_) => {}\n        Err(status) => panic!(\"{}\", status.message()),\n    }\n\n    tx.send(()).unwrap();\n\n    jh.await.unwrap();\n}\n"
  },
  {
    "path": "tests/web/Cargo.toml",
    "content": "[package]\nauthors = [\"Juan Alvarez <j@yabit.io>\"]\nedition = \"2021\"\nname = \"test_web\"\nlicense = \"MIT\"\n\n[dependencies]\nbase64 = \"0.22\"\nbytes = \"1.0\"\nhttp-body-util = \"0.1\"\nhyper = \"1\"\nhyper-util = \"0.1\"\nprost = \"0.14\"\ntokio = { version = \"1\", features = [\"macros\", \"rt\", \"net\"] }\ntokio-stream = { version = \"0.1\", features = [\"net\"] }\ntonic = { path = \"../../tonic\" }\ntonic-prost = { path = \"../../tonic-prost\" }\n\n[dev-dependencies]\ntonic-web = { path = \"../../tonic-web\" }\n\n[build-dependencies]\ntonic-prost-build = { path = \"../../tonic-prost-build\" }\n"
  },
  {
    "path": "tests/web/build.rs",
    "content": "fn main() {\n    let protos = &[\"proto/test.proto\"];\n\n    tonic_prost_build::configure()\n        .compile_protos(protos, &[\"proto\"])\n        .unwrap();\n\n    protos\n        .iter()\n        .for_each(|file| println!(\"cargo:rerun-if-changed={file}\"));\n}\n"
  },
  {
    "path": "tests/web/proto/test.proto",
    "content": "syntax = \"proto3\";\n\npackage test;\n\nservice Test {\n  rpc UnaryCall(Input) returns (Output);\n  rpc ServerStream(Input) returns (stream Output);\n  rpc ClientStream(stream Input) returns (Output);\n}\n\nmessage Input {\n  int32 id = 1;\n  string desc = 2;\n}\n\nmessage Output {\n  int32 id = 1;\n  string desc = 2;\n}\n"
  },
  {
    "path": "tests/web/src/lib.rs",
    "content": "use std::pin::Pin;\n\nuse tokio_stream::{self as stream, Stream, StreamExt};\nuse tonic::{Request, Response, Status, Streaming};\n\nuse pb::{test_server::Test, Input, Output};\n\npub mod pb {\n    tonic::include_proto!(\"test\");\n}\n\ntype BoxStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send + 'static>>;\n\npub struct Svc;\n\n#[tonic::async_trait]\nimpl Test for Svc {\n    async fn unary_call(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n        let req = req.into_inner();\n\n        if &req.desc == \"boom\" {\n            Err(Status::invalid_argument(\"invalid boom\"))\n        } else {\n            Ok(Response::new(Output {\n                id: req.id,\n                desc: req.desc,\n            }))\n        }\n    }\n\n    type ServerStreamStream = BoxStream<Output>;\n\n    async fn server_stream(\n        &self,\n        req: Request<Input>,\n    ) -> Result<Response<Self::ServerStreamStream>, Status> {\n        let req = req.into_inner();\n\n        Ok(Response::new(Box::pin(stream::iter(vec![1, 2]).map(\n            move |n| {\n                Ok(Output {\n                    id: req.id,\n                    desc: format!(\"{}-{}\", n, req.desc),\n                })\n            },\n        ))))\n    }\n\n    async fn client_stream(\n        &self,\n        req: Request<Streaming<Input>>,\n    ) -> Result<Response<Output>, Status> {\n        let out = Output {\n            id: 0,\n            desc: \"\".into(),\n        };\n\n        Ok(Response::new(\n            req.into_inner()\n                .fold(out, |mut acc, input| {\n                    let input = input.unwrap();\n                    acc.id += input.id;\n                    acc.desc += &input.desc;\n                    acc\n                })\n                .await,\n        ))\n    }\n}\n\npub mod util {\n    pub mod base64 {\n        use base64::{\n            alphabet,\n            engine::{\n                general_purpose::{GeneralPurpose, GeneralPurposeConfig},\n                DecodePaddingMode,\n            },\n        };\n\n        pub const STANDARD: GeneralPurpose = GeneralPurpose::new(\n            &alphabet::STANDARD,\n            GeneralPurposeConfig::new()\n                .with_encode_padding(true)\n                .with_decode_padding_mode(DecodePaddingMode::Indifferent),\n        );\n    }\n}\n"
  },
  {
    "path": "tests/web/tests/grpc.rs",
    "content": "use std::future::Future;\nuse std::net::SocketAddr;\n\nuse tokio::net::TcpListener;\nuse tokio::time::Duration;\nuse tokio::{join, try_join};\nuse tokio_stream::wrappers::TcpListenerStream;\nuse tokio_stream::{self as stream, StreamExt};\nuse tonic::transport::{Channel, Error, Server};\nuse tonic::{Response, Streaming};\n\nuse test_web::pb::{test_client::TestClient, test_server::TestServer, Input};\nuse test_web::Svc;\nuse tonic_web::GrpcWebLayer;\n\n#[tokio::test]\nasync fn smoke_unary() {\n    let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect(\"clients\");\n\n    let (r1, r2, r3, r4) = try_join!(\n        c1.unary_call(input()),\n        c2.unary_call(input()),\n        c3.unary_call(input()),\n        c4.unary_call(input()),\n    )\n    .expect(\"responses\");\n\n    assert!(meta(&r1) == meta(&r2) && meta(&r2) == meta(&r3) && meta(&r3) == meta(&r4));\n    assert!(data(&r1) == data(&r2) && data(&r2) == data(&r3) && data(&r3) == data(&r4));\n}\n\n#[tokio::test]\nasync fn smoke_client_stream() {\n    let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect(\"clients\");\n\n    let input_stream = || stream::iter(vec![input(), input()]);\n\n    let (r1, r2, r3, r4) = try_join!(\n        c1.client_stream(input_stream()),\n        c2.client_stream(input_stream()),\n        c3.client_stream(input_stream()),\n        c4.client_stream(input_stream()),\n    )\n    .expect(\"responses\");\n\n    assert!(meta(&r1) == meta(&r2) && meta(&r2) == meta(&r3) && meta(&r3) == meta(&r4));\n    assert!(data(&r1) == data(&r2) && data(&r2) == data(&r3) && data(&r3) == data(&r4));\n}\n\n#[tokio::test]\nasync fn smoke_server_stream() {\n    let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect(\"clients\");\n\n    let (r1, r2, r3, r4) = try_join!(\n        c1.server_stream(input()),\n        c2.server_stream(input()),\n        c3.server_stream(input()),\n        c4.server_stream(input()),\n    )\n    .expect(\"responses\");\n\n    assert!(meta(&r1) == meta(&r2) && meta(&r2) == meta(&r3) && meta(&r3) == meta(&r4));\n\n    let r1 = stream(r1).await;\n    let r2 = stream(r2).await;\n    let r3 = stream(r3).await;\n    let r4 = stream(r4).await;\n\n    assert!(r1 == r2 && r2 == r3 && r3 == r4);\n}\n#[tokio::test]\nasync fn smoke_error() {\n    let (mut c1, mut c2, mut c3, mut c4) = spawn().await.expect(\"clients\");\n\n    let boom = Input {\n        id: 1,\n        desc: \"boom\".to_owned(),\n    };\n\n    let (r1, r2, r3, r4) = join!(\n        c1.unary_call(boom.clone()),\n        c2.unary_call(boom.clone()),\n        c3.unary_call(boom.clone()),\n        c4.unary_call(boom.clone()),\n    );\n\n    let s1 = r1.unwrap_err();\n    let s2 = r2.unwrap_err();\n    let s3 = r3.unwrap_err();\n    let s4 = r4.unwrap_err();\n\n    assert!(status(&s1) == status(&s2) && status(&s2) == status(&s3) && status(&s3) == status(&s4))\n}\n\nasync fn bind() -> (TcpListener, String) {\n    let addr = SocketAddr::from(([127, 0, 0, 1], 0));\n    let lis = TcpListener::bind(addr).await.expect(\"listener\");\n    let url = format!(\"http://{}\", lis.local_addr().unwrap());\n\n    (lis, url)\n}\n\nasync fn grpc(accept_h1: bool) -> (impl Future<Output = Result<(), Error>>, String) {\n    let (listener, url) = bind().await;\n\n    let fut = Server::builder()\n        .accept_http1(accept_h1)\n        .add_service(TestServer::new(Svc))\n        .serve_with_incoming(TcpListenerStream::new(listener));\n\n    (fut, url)\n}\n\nasync fn grpc_web(accept_h1: bool) -> (impl Future<Output = Result<(), Error>>, String) {\n    let (listener, url) = bind().await;\n\n    let fut = Server::builder()\n        .accept_http1(accept_h1)\n        .layer(GrpcWebLayer::new())\n        .add_service(TestServer::new(Svc))\n        .serve_with_incoming(TcpListenerStream::new(listener));\n\n    (fut, url)\n}\n\ntype Client = TestClient<Channel>;\n\nasync fn spawn() -> Result<(Client, Client, Client, Client), Error> {\n    let ((s1, u1), (s2, u2), (s3, u3), (s4, u4)) =\n        join!(grpc(true), grpc(false), grpc_web(true), grpc_web(false));\n\n    drop(tokio::spawn(async move { join!(s1, s2, s3, s4) }));\n\n    tokio::time::sleep(Duration::from_millis(30)).await;\n\n    try_join!(\n        TestClient::connect(u1),\n        TestClient::connect(u2),\n        TestClient::connect(u3),\n        TestClient::connect(u4)\n    )\n}\n\nfn input() -> Input {\n    Input {\n        id: 1,\n        desc: \"one\".to_owned(),\n    }\n}\n\nfn meta<T>(r: &Response<T>) -> String {\n    format!(\"{:?}\", r.metadata())\n}\n\nfn data<T>(r: &Response<T>) -> &T {\n    r.get_ref()\n}\n\nasync fn stream<T>(r: Response<Streaming<T>>) -> Vec<T> {\n    r.into_inner().collect::<Result<Vec<_>, _>>().await.unwrap()\n}\n\nfn status(s: &tonic::Status) -> (String, tonic::Code) {\n    (format!(\"{:?}\", s.metadata()), s.code())\n}\n"
  },
  {
    "path": "tests/web/tests/grpc_web.rs",
    "content": "use std::net::SocketAddr;\n\nuse base64::Engine as _;\nuse bytes::{Buf, BufMut, Bytes, BytesMut};\nuse http_body_util::{BodyExt as _, Full};\nuse hyper::body::Incoming;\nuse hyper::http::{header, StatusCode};\nuse hyper::{Method, Request, Uri};\nuse hyper_util::client::legacy::Client;\nuse hyper_util::rt::TokioExecutor;\nuse prost::Message;\nuse tokio::net::TcpListener;\nuse tokio_stream::wrappers::TcpListenerStream;\nuse tonic::body::Body;\nuse tonic::transport::Server;\n\nuse test_web::pb::{test_server::TestServer, Input, Output};\nuse test_web::Svc;\nuse tonic::Status;\nuse tonic_web::GrpcWebLayer;\n\n#[tokio::test]\nasync fn binary_request() {\n    let server_url = spawn().await;\n    let client = Client::builder(TokioExecutor::new()).build_http();\n\n    let req = build_request(server_url, \"grpc-web\", \"grpc-web\");\n    let res = client.request(req).await.unwrap();\n    let content_type = res.headers().get(header::CONTENT_TYPE).unwrap().clone();\n    let content_type = content_type.to_str().unwrap();\n\n    assert_eq!(res.status(), StatusCode::OK);\n    assert_eq!(content_type, \"application/grpc-web+proto\");\n\n    let (message, trailers) = decode_body(res.into_body(), content_type).await;\n    let expected = Output {\n        id: 1,\n        desc: \"one\".to_owned(),\n    };\n\n    assert_eq!(message, expected);\n    assert_eq!(&trailers[..], b\"grpc-status:0\\r\\n\");\n}\n\n#[tokio::test]\nasync fn text_request() {\n    let server_url = spawn().await;\n    let client = Client::builder(TokioExecutor::new()).build_http();\n\n    let req = build_request(server_url, \"grpc-web-text\", \"grpc-web-text\");\n    let res = client.request(req).await.unwrap();\n    let content_type = res.headers().get(header::CONTENT_TYPE).unwrap().clone();\n    let content_type = content_type.to_str().unwrap();\n\n    assert_eq!(res.status(), StatusCode::OK);\n    assert_eq!(content_type, \"application/grpc-web-text+proto\");\n\n    let (message, trailers) = decode_body(res.into_body(), content_type).await;\n    let expected = Output {\n        id: 1,\n        desc: \"one\".to_owned(),\n    };\n\n    assert_eq!(message, expected);\n    assert_eq!(&trailers[..], b\"grpc-status:0\\r\\n\");\n}\n\nasync fn spawn() -> String {\n    let addr = SocketAddr::from(([127, 0, 0, 1], 0));\n    let listener = TcpListener::bind(addr).await.expect(\"listener\");\n    let url = format!(\"http://{}\", listener.local_addr().unwrap());\n    let listener_stream = TcpListenerStream::new(listener);\n\n    drop(tokio::spawn(async move {\n        Server::builder()\n            .accept_http1(true)\n            .layer(GrpcWebLayer::new())\n            .add_service(TestServer::new(Svc))\n            .serve_with_incoming(listener_stream)\n            .await\n            .unwrap()\n    }));\n\n    url\n}\n\nfn encode_body() -> Bytes {\n    let input = Input {\n        id: 1,\n        desc: \"one\".to_owned(),\n    };\n\n    let mut buf = BytesMut::with_capacity(1024);\n    buf.reserve(5);\n    unsafe {\n        buf.advance_mut(5);\n    }\n\n    input.encode(&mut buf).unwrap();\n\n    let len = buf.len() - 5;\n    {\n        let mut buf = &mut buf[..5];\n        buf.put_u8(0);\n        buf.put_u32(len as u32);\n    }\n\n    buf.split_to(len + 5).freeze()\n}\n\nfn build_request(base_uri: String, content_type: &str, accept: &str) -> Request<Body> {\n    use header::{ACCEPT, CONTENT_TYPE, ORIGIN};\n\n    let request_uri = format!(\"{}/{}/{}\", base_uri, \"test.Test\", \"UnaryCall\")\n        .parse::<Uri>()\n        .unwrap();\n\n    let bytes = match content_type {\n        \"grpc-web\" => encode_body(),\n        \"grpc-web-text\" => test_web::util::base64::STANDARD\n            .encode(encode_body())\n            .into(),\n        _ => panic!(\"invalid content type {content_type}\"),\n    };\n\n    Request::builder()\n        .method(Method::POST)\n        .header(CONTENT_TYPE, format!(\"application/{content_type}\"))\n        .header(ORIGIN, \"http://example.com\")\n        .header(ACCEPT, format!(\"application/{accept}\"))\n        .uri(request_uri)\n        .body(Body::new(\n            Full::new(bytes).map_err(|err| Status::internal(err.to_string())),\n        ))\n        .unwrap()\n}\n\nasync fn decode_body(body: Incoming, content_type: &str) -> (Output, Bytes) {\n    let mut body = body.collect().await.unwrap().to_bytes();\n\n    if content_type == \"application/grpc-web-text+proto\" {\n        body = test_web::util::base64::STANDARD\n            .decode(body)\n            .unwrap()\n            .into()\n    }\n\n    body.advance(1);\n    let len = body.get_u32();\n    let msg = Output::decode(&mut body.split_to(len as usize)).expect(\"decode\");\n    body.advance(5);\n\n    (msg, body)\n}\n"
  },
  {
    "path": "tests/wellknown/Cargo.toml",
    "content": "[package]\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"wellknown\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nprost = \"0.14\"\nprost-types = \"0.14\"\ntonic = {path = \"../../tonic\"}\ntonic-prost = {path = \"../../tonic-prost\"}\n\n[build-dependencies]\ntonic-prost-build = {path = \"../../tonic-prost-build\"}\n"
  },
  {
    "path": "tests/wellknown/build.rs",
    "content": "fn main() {\n    tonic_prost_build::compile_protos(\"proto/wellknown.proto\").unwrap();\n}\n"
  },
  {
    "path": "tests/wellknown/proto/wellknown.proto",
    "content": "syntax = \"proto3\";\n\npackage wellknown;\n\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/wrappers.proto\";\nimport \"google/protobuf/any.proto\";\n\nservice Admin {\n  rpc EmptyCall(google.protobuf.Empty) returns (google.protobuf.Empty);\n  rpc StringCall(google.protobuf.StringValue) returns (google.protobuf.Empty);\n  rpc AnyCall(google.protobuf.Any) returns (google.protobuf.Empty);\n}\n"
  },
  {
    "path": "tests/wellknown/src/lib.rs",
    "content": "pub mod pb {\n    tonic::include_proto!(\"wellknown\");\n}\n"
  },
  {
    "path": "tests/wellknown-compiled/Cargo.toml",
    "content": "[package]\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2021\"\nlicense = \"MIT\"\nname = \"wellknown-compiled\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[lib]\ndoctest = false\n\n[dependencies]\nprost = \"0.14\"\ntonic = {path = \"../../tonic\"}\ntonic-prost = {path = \"../../tonic-prost\"}\n\n[build-dependencies]\ntonic-prost-build = {path = \"../../tonic-prost-build\"}\n"
  },
  {
    "path": "tests/wellknown-compiled/build.rs",
    "content": "fn main() {\n    tonic_prost_build::configure()\n        .extern_path(\".google.protobuf.Empty\", \"()\")\n        .compile_well_known_types(true)\n        .compile_protos(&[\"proto/google.proto\", \"proto/test.proto\"], &[\"proto\"])\n        .unwrap();\n}\n"
  },
  {
    "path": "tests/wellknown-compiled/proto/google.proto",
    "content": "syntax = \"proto3\";\n\npackage google.protobuf;\n\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/api.proto\";\nimport \"google/protobuf/descriptor.proto\";\nimport \"google/protobuf/duration.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/field_mask.proto\";\nimport \"google/protobuf/source_context.proto\";\nimport \"google/protobuf/struct.proto\";\nimport \"google/protobuf/timestamp.proto\";\nimport \"google/protobuf/type.proto\";\nimport \"google/protobuf/wrappers.proto\";\n\n"
  },
  {
    "path": "tests/wellknown-compiled/proto/test.proto",
    "content": "syntax = \"proto3\";\npackage test;\n\nimport \"google/protobuf/empty.proto\";\n\nmessage Input {\n}\n\nservice Service {\n  rpc Call(Input) returns (google.protobuf.Empty);\n}\n"
  },
  {
    "path": "tests/wellknown-compiled/src/lib.rs",
    "content": "pub mod gen {\n    pub mod google {\n        pub mod protobuf {\n            #![allow(clippy::doc_overindented_list_items)]\n            tonic::include_proto!(\"google.protobuf\");\n        }\n    }\n\n    pub mod test {\n        tonic::include_proto!(\"test\");\n    }\n}\n\npub fn grok() {\n    let _any = crate::gen::google::protobuf::Any {\n        type_url: \"foo\".to_owned(),\n        value: Vec::new(),\n    };\n}\n"
  },
  {
    "path": "tonic/Cargo.toml",
    "content": "[package]\nname = \"tonic\"\n# When releasing to crates.io:\n# - Remove path dependencies\n# - Update CHANGELOG.md.\n# - Create \"v0.11.x\" git tag.\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\ncategories = [\"web-programming\", \"network-programming\", \"asynchronous\"]\ndescription = \"\"\"\nA gRPC over HTTP/2 implementation focused on high performance, interoperability, and flexibility.\n\"\"\"\nedition = \"2024\"\nhomepage = \"https://github.com/hyperium/tonic\"\nkeywords = [\"rpc\", \"grpc\", \"async\", \"futures\", \"protobuf\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/hyperium/tonic\"\nversion = \"0.14.5\"\nrust-version = {workspace = true}\nexclude = [\"benches-disabled\"]\n\n[features]\ncodegen = [\"dep:async-trait\"]\ngzip = [\"dep:flate2\"]\ndeflate = [\"dep:flate2\"]\nzstd = [\"dep:zstd\"]\ndefault = [\"router\", \"transport\", \"codegen\"]\n_tls-any = [\"dep:tokio\", \"tokio?/rt\", \"tokio?/macros\", \"tls-connect-info\"] # Internal. Please choose one of `tls-ring` or `tls-aws-lc`\ntls-ring = [\"_tls-any\", \"tokio-rustls/ring\"]\ntls-aws-lc = [\"_tls-any\", \"tokio-rustls/aws-lc-rs\"]\ntls-native-roots = [\"_tls-any\", \"channel\", \"dep:rustls-native-certs\"]\ntls-webpki-roots = [\"_tls-any\",\"channel\", \"dep:webpki-roots\"]\ntls-connect-info = [\"dep:tokio-rustls\"]\nrouter = [\"dep:axum\", \"dep:tower\", \"tower?/util\"]\nserver = [\n  \"dep:h2\",\n  \"dep:hyper\", \"hyper?/server\",\n  \"dep:hyper-util\", \"hyper-util?/service\", \"hyper-util?/server-auto\",\n  \"dep:socket2\",\n  \"dep:tokio\", \"tokio?/macros\", \"tokio?/net\", \"tokio?/time\",\n  \"tokio-stream/net\",\n  \"dep:tower\", \"tower?/util\", \"tower?/limit\", \"tower?/load-shed\",\n]\nchannel = [\n  \"dep:hyper\", \"hyper?/client\",\n  \"dep:hyper-util\", \"hyper-util?/client-legacy\",\n  \"dep:tower\", \"tower?/balance\", \"tower?/buffer\", \"tower?/discover\", \"tower?/limit\", \"tower?/load-shed\", \"tower?/util\",\n  \"dep:tokio\", \"tokio?/time\",\n  \"dep:hyper-timeout\",\n]\ntransport = [\"server\", \"channel\"]\n\n# [[bench]]\n# name = \"bench_main\"\n# harness = false\n\n[dependencies]\nbase64 = \"0.22\"\nbytes = \"1.0\"\nhttp = \"1.1.0\"\ntracing = \"0.1\"\n\nhttp-body = \"1\"\nhttp-body-util = \"0.1\"\npercent-encoding = \"2.1\"\npin-project = \"1.0.11\"\ntower-layer = \"0.3\"\ntower-service = \"0.3\"\ntokio-stream = {version = \"0.1.16\", default-features = false}\n\n\n# codegen\nasync-trait = {version = \"0.1.13\", optional = true}\n\n# transport\nh2 = {version = \"0.4\", optional = true}\nhyper = {version = \"1\", features = [\"http1\", \"http2\"], optional = true}\nhyper-util = { version = \"0.1.11\", features = [\"tokio\"], optional = true }\nsocket2 = { version = \"0.6\", optional = true, features = [\"all\"] }\ntokio = {version = \"1\", default-features = false, optional = true}\ntower = {version = \"0.5\", default-features = false, optional = true}\naxum = {version = \"0.8\", default-features = false, optional = true}\n\n# rustls\nrustls-native-certs = { version = \"0.8\", optional = true }\ntokio-rustls = { version = \"0.26.1\", default-features = false, features = [\"logging\", \"tls12\"], optional = true }\nwebpki-roots = { version = \"1\", optional = true }\n\n# compression\nflate2 = {version = \"1.0\", optional = true}\nzstd = { version = \"0.13.0\", optional = true }\n\n# channel\nhyper-timeout = {version = \"0.5\", optional = true}\nsync_wrapper = \"1.0.2\"\n\n[dev-dependencies]\nbencher = \"0.1.5\"\nquickcheck = \"1.0\"\nquickcheck_macros = \"1.0\"\nstatic_assertions = \"1.0\"\ntokio = {version = \"1.0\", features = [\"rt-multi-thread\", \"macros\", \"test-util\"]}\ntower = {version = \"0.5\", features = [\"load-shed\", \"timeout\"]}\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nall-features = true\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  # major released\n  \"bytes::*\",\n  \"tokio::*\",\n  \"http::*\",\n  \"http_body::*\",\n  \"hyper::*\",\n  \"rustls_pki_types::*\",\n\n  # not major released\n  \"prost::*\",\n  \"tracing::*\",\n\n  \"async_trait::async_trait\",\n  \"axum_core::body::Body\",\n  \"axum_core::response::into_response::IntoResponse\",\n  \"axum::routing::Router\",\n  \"futures_core::stream::Stream\",\n  \"h2::error::Error\",\n  \"tower_service::Service\",\n  \"tower_layer::Layer\",\n  \"tower_layer::stack::Stack\",\n  \"tower_layer::identity::Identity\",\n]\n\n[[bench]]\nharness = false\nname = \"decode\"\n"
  },
  {
    "path": "tonic/benches/decode.rs",
    "content": "#![allow(missing_docs)]\n\nuse bencher::{Bencher, benchmark_group, benchmark_main};\nuse bytes::{Buf, BufMut, Bytes, BytesMut};\nuse http_body::{Body, Frame, SizeHint};\nuse std::{\n    fmt::{Error, Formatter},\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tonic::{Status, Streaming, codec::DecodeBuf, codec::Decoder};\n\nmacro_rules! bench {\n    ($name:ident, $message_size:expr, $chunk_size:expr, $message_count:expr) => {\n        fn $name(b: &mut Bencher) {\n            let rt = tokio::runtime::Builder::new_multi_thread()\n                .build()\n                .expect(\"runtime\");\n\n            let payload = make_payload($message_size, $message_count);\n            let body = MockBody::new(payload, $chunk_size);\n            b.bytes = body.len() as u64;\n\n            b.iter(|| {\n                rt.block_on(async {\n                    let decoder = MockDecoder::new($message_size);\n                    let mut stream = Streaming::new_request(decoder, body.clone(), None, None);\n\n                    let mut count = 0;\n                    while let Some(msg) = stream.message().await.unwrap() {\n                        assert_eq!($message_size, msg.len());\n                        count += 1;\n                    }\n\n                    assert_eq!(count, $message_count);\n                    assert!(stream.trailers().await.unwrap().is_none());\n                })\n            })\n        }\n    };\n}\n\n#[derive(Clone)]\nstruct MockBody {\n    data: Bytes,\n    chunk_size: usize,\n}\n\nimpl MockBody {\n    fn new(data: Bytes, chunk_size: usize) -> Self {\n        MockBody { data, chunk_size }\n    }\n\n    fn len(&self) -> usize {\n        self.data.len()\n    }\n}\n\nimpl Body for MockBody {\n    type Data = Bytes;\n    type Error = Status;\n\n    fn poll_frame(\n        mut self: Pin<&mut Self>,\n        _cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        if self.data.has_remaining() {\n            let split = std::cmp::min(self.chunk_size, self.data.remaining());\n            Poll::Ready(Some(Ok(Frame::data(self.data.split_to(split)))))\n        } else {\n            Poll::Ready(None)\n        }\n    }\n\n    fn is_end_stream(&self) -> bool {\n        self.data.is_empty()\n    }\n\n    fn size_hint(&self) -> SizeHint {\n        SizeHint::with_exact(self.data.len() as u64)\n    }\n}\n\nimpl std::fmt::Debug for MockBody {\n    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {\n        let sample = self.data.iter().take(10).collect::<Vec<_>>();\n        write!(f, \"{:?}...({})\", sample, self.data.len())\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct MockDecoder {\n    message_size: usize,\n}\n\nimpl MockDecoder {\n    fn new(message_size: usize) -> Self {\n        MockDecoder { message_size }\n    }\n}\n\nimpl Decoder for MockDecoder {\n    type Item = Vec<u8>;\n    type Error = Status;\n\n    fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result<Option<Self::Item>, Self::Error> {\n        let out = Vec::from(buf.chunk());\n        buf.advance(self.message_size);\n        Ok(Some(out))\n    }\n}\n\nfn make_payload(message_length: usize, message_count: usize) -> Bytes {\n    let mut buf = BytesMut::new();\n\n    for _ in 0..message_count {\n        let msg = vec![97u8; message_length];\n        buf.reserve(msg.len() + 5);\n        buf.put_u8(0);\n        buf.put_u32(msg.len() as u32);\n        buf.put(&msg[..]);\n    }\n\n    buf.freeze()\n}\n\n// change body chunk size only\nbench!(chunk_size_100, 1_000, 100, 1);\nbench!(chunk_size_500, 1_000, 500, 1);\nbench!(chunk_size_1005, 1_000, 1_005, 1);\n\n// change message size only\nbench!(message_size_1k, 1_000, 1_005, 2);\nbench!(message_size_5k, 5_000, 1_005, 2);\nbench!(message_size_10k, 10_000, 1_005, 2);\n\n// change message count only\nbench!(message_count_1, 500, 505, 1);\nbench!(message_count_10, 500, 505, 10);\nbench!(message_count_20, 500, 505, 20);\n\nbenchmark_group!(chunk_size, chunk_size_100, chunk_size_500, chunk_size_1005);\n\nbenchmark_group!(\n    message_size,\n    message_size_1k,\n    message_size_5k,\n    message_size_10k\n);\n\nbenchmark_group!(\n    message_count,\n    message_count_1,\n    message_count_10,\n    message_count_20\n);\n\nbenchmark_main!(chunk_size, message_size, message_count);\n"
  },
  {
    "path": "tonic/benches-disabled/README.md",
    "content": "## Criterion benchmarks for Tonic\n\n### Running the benchmarks \nFrom the root Tonic directory, `cargo bench`\n\nAfter running, the reports can be found in `tonic/target/criterion/report/index.html`\n\n[Gnuplot](http://www.gnuplot.info/) is required for graph generation.  If gnuplot is not installed, Criterion will display: `Gnuplot not found, disabling plotting` at the console.\n\n### Notes \n1) Currently, these benchmarks only test the performance of constructing Tonic Requests and Responses, not over-the-wire throughput. \n2) The `thrpt` value generated by Criterion is simply a measure of bytes consumed by the target function.\n3) As we are not testing tonic-build compile time, the tests reference pre-compiled .rs files in 'benchmarks/compiled_protos'.\n4) The original proto files are in the `proto` directory for reference.  \n5) This used the Criterion 3.0 `Criterion Group` functionality. Details here: https://docs.rs/criterion/0.3.0/criterion/  \n\n### Interpreting Results\n\nCriterion is particularly useful for establishing a first-run baseline and then comparing after code-changes - e.g. `Performance has regressed` below. \n\n```bash\nRequest_Response/request/100000                                                                             \n                        time:   [2.7231 us 2.7588 us 2.7969 us]\n                        thrpt:  [33.298 GiB/s 33.758 GiB/s 34.200 GiB/s]\n                 change:\n                        time:   [+16.073% +17.871% +19.980%] (p = 0.00 < 0.05)\n                        thrpt:  [-16.653% -15.162% -13.847%]\n                        Performance has regressed.\nFound 3 outliers among 100 measurements (3.00%)\n  1 (1.00%) high mild\n  2 (2.00%) high severe\n```\n\n\n\n\n\n"
  },
  {
    "path": "tonic/benches-disabled/bench_main.rs",
    "content": "#![cfg(feature = \"broken\")]\n\nuse criterion::*;\n\nmod benchmarks;\n\ncriterion_group!(\n    benches,\n    benchmarks::request_response::bench_throughput,\n    benchmarks::request_response_diverse_types::bench_throughput,\n);\ncriterion_main!(benches);\n"
  },
  {
    "path": "tonic/benches-disabled/benchmarks/compiled_protos/diverse_types.rs",
    "content": "#[derive(Clone, PartialEq, ::prost::Message)]\npub struct GoogleMessage1 {\n    #[prost(string, tag = \"1\")]\n    pub field1: std::string::String,\n    #[prost(string, tag = \"9\")]\n    pub field9: std::string::String,\n    #[prost(string, tag = \"18\")]\n    pub field18: std::string::String,\n    #[prost(bool, tag = \"80\")]\n    pub field80: bool,\n    #[prost(bool, tag = \"81\")]\n    pub field81: bool,\n    #[prost(int32, tag = \"2\")]\n    pub field2: i32,\n    #[prost(int32, tag = \"3\")]\n    pub field3: i32,\n    #[prost(int32, tag = \"280\")]\n    pub field280: i32,\n    #[prost(int32, tag = \"6\")]\n    pub field6: i32,\n    #[prost(int64, tag = \"22\")]\n    pub field22: i64,\n    #[prost(string, tag = \"4\")]\n    pub field4: std::string::String,\n    #[prost(fixed64, repeated, tag = \"5\")]\n    pub field5: ::std::vec::Vec<u64>,\n    #[prost(bool, tag = \"59\")]\n    pub field59: bool,\n    #[prost(string, tag = \"7\")]\n    pub field7: std::string::String,\n    #[prost(int32, tag = \"16\")]\n    pub field16: i32,\n    #[prost(int32, tag = \"130\")]\n    pub field130: i32,\n    #[prost(bool, tag = \"12\")]\n    pub field12: bool,\n    #[prost(bool, tag = \"17\")]\n    pub field17: bool,\n    #[prost(bool, tag = \"13\")]\n    pub field13: bool,\n    #[prost(bool, tag = \"14\")]\n    pub field14: bool,\n    #[prost(int32, tag = \"104\")]\n    pub field104: i32,\n    #[prost(int32, tag = \"100\")]\n    pub field100: i32,\n    #[prost(int32, tag = \"101\")]\n    pub field101: i32,\n    #[prost(string, tag = \"102\")]\n    pub field102: std::string::String,\n    #[prost(string, tag = \"103\")]\n    pub field103: std::string::String,\n    #[prost(int32, tag = \"29\")]\n    pub field29: i32,\n    #[prost(bool, tag = \"30\")]\n    pub field30: bool,\n    #[prost(int32, tag = \"60\")]\n    pub field60: i32,\n    #[prost(int32, tag = \"271\")]\n    pub field271: i32,\n    #[prost(int32, tag = \"272\")]\n    pub field272: i32,\n    #[prost(int32, tag = \"150\")]\n    pub field150: i32,\n    #[prost(int32, tag = \"23\")]\n    pub field23: i32,\n    #[prost(bool, tag = \"24\")]\n    pub field24: bool,\n    #[prost(int32, tag = \"25\")]\n    pub field25: i32,\n    #[prost(message, optional, tag = \"15\")]\n    pub field15: ::std::option::Option<GoogleMessage1SubMessage>,\n    #[prost(bool, tag = \"78\")]\n    pub field78: bool,\n    #[prost(int32, tag = \"67\")]\n    pub field67: i32,\n    #[prost(int32, tag = \"68\")]\n    pub field68: i32,\n    #[prost(int32, tag = \"128\")]\n    pub field128: i32,\n    #[prost(string, tag = \"129\")]\n    pub field129: std::string::String,\n    #[prost(int32, tag = \"131\")]\n    pub field131: i32,\n}\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct GoogleMessage1SubMessage {\n    #[prost(int32, tag = \"1\")]\n    pub field1: i32,\n    #[prost(int32, tag = \"2\")]\n    pub field2: i32,\n    #[prost(int32, tag = \"3\")]\n    pub field3: i32,\n    #[prost(string, tag = \"15\")]\n    pub field15: std::string::String,\n    #[prost(bool, tag = \"12\")]\n    pub field12: bool,\n    #[prost(int64, tag = \"13\")]\n    pub field13: i64,\n    #[prost(int64, tag = \"14\")]\n    pub field14: i64,\n    #[prost(int32, tag = \"16\")]\n    pub field16: i32,\n    #[prost(int32, tag = \"19\")]\n    pub field19: i32,\n    #[prost(bool, tag = \"20\")]\n    pub field20: bool,\n    #[prost(bool, tag = \"28\")]\n    pub field28: bool,\n    #[prost(fixed64, tag = \"21\")]\n    pub field21: u64,\n    #[prost(int32, tag = \"22\")]\n    pub field22: i32,\n    #[prost(bool, tag = \"23\")]\n    pub field23: bool,\n    #[prost(bool, tag = \"206\")]\n    pub field206: bool,\n    #[prost(fixed32, tag = \"203\")]\n    pub field203: u32,\n    #[prost(int32, tag = \"204\")]\n    pub field204: i32,\n    #[prost(string, tag = \"205\")]\n    pub field205: std::string::String,\n    #[prost(uint64, tag = \"207\")]\n    pub field207: u64,\n    #[prost(uint64, tag = \"300\")]\n    pub field300: u64,\n}\n"
  },
  {
    "path": "tonic/benches-disabled/benchmarks/compiled_protos/helloworld.rs",
    "content": "/// The request message containing the user's name.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct HelloRequest {\n    #[prost(string, tag = \"1\")]\n    pub name: std::string::String,\n}\n/// The response message containing the greetings\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct HelloReply {\n    #[prost(string, tag = \"1\")]\n    pub message: std::string::String,\n}\n#[doc = r\" Generated client implementations.\"]\npub mod client {\n    #![allow(unused_variables, dead_code, missing_docs)]\n    use tonic::codegen::*;\n    #[doc = \" The greeting service definition.\"]\n    pub struct GreeterClient<T> {\n        inner: tonic::client::Grpc<T>,\n    }\n    impl GreeterClient<tonic::transport::Channel> {\n        #[doc = r\" Attempt to create a new client by connecting to a given endpoint.\"]\n        pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>\n        where\n            D: TryInto<tonic::transport::Endpoint>,\n            D::Error: Into<StdError>,\n        {\n            let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;\n            Ok(Self::new(conn))\n        }\n    }\n    impl<T> GreeterClient<T>\n    where\n        T: tonic::client::GrpcService<tonic::body::BoxBody>,\n        T::ResponseBody: Body + Send + 'static,\n        T::Error: Into<StdError>,\n        <T::ResponseBody as Body>::Error: Into<StdError> + Send,\n        <T::ResponseBody as Body>::Data: Into<bytes::Bytes> + Send,\n    {\n        pub fn new(inner: T) -> Self {\n            let inner = tonic::client::Grpc::new(inner);\n            Self { inner }\n        }\n        #[doc = r\" Check if the service is ready.\"]\n        pub async fn ready(&mut self) -> Result<(), tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::new(\n                    tonic::Code::Unknown,\n                    format!(\"Service was not ready: {}\", e.into()),\n                )\n            })\n        }\n        #[doc = \" Sends a greeting\"]\n        pub async fn say_hello(\n            &mut self,\n            request: tonic::Request<super::HelloRequest>,\n        ) -> Result<tonic::Response<super::HelloReply>, tonic::Status> {\n            self.ready().await?;\n            let codec = tonic::codec::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\"/helloworld.Greeter/SayHello\");\n            self.inner.unary(request, path, codec).await\n        }\n    }\n    impl<T: Clone> Clone for GreeterClient<T> {\n        fn clone(&self) -> Self {\n            Self {\n                inner: self.inner.clone(),\n            }\n        }\n    }\n}\n#[doc = r\" Generated server implementations.\"]\npub mod server {\n    #![allow(unused_variables, dead_code, missing_docs)]\n    use tonic::codegen::*;\n    #[doc = \"Generated trait containing gRPC methods that should be implemented for use with GreeterServer.\"]\n    #[async_trait]\n    pub trait Greeter: Send + Sync + 'static {\n        #[doc = \" Sends a greeting\"]\n        async fn say_hello(\n            &self,\n            request: tonic::Request<super::HelloRequest>,\n        ) -> Result<tonic::Response<super::HelloReply>, tonic::Status> {\n            Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n        }\n    }\n    #[doc = \" The greeting service definition.\"]\n    #[derive(Clone, Debug)]\n    pub struct GreeterServer<T: Greeter> {\n        inner: Arc<T>,\n    }\n    #[derive(Clone, Debug)]\n    #[doc(hidden)]\n    pub struct GreeterServerSvc<T: Greeter> {\n        inner: Arc<T>,\n    }\n    impl<T: Greeter> GreeterServer<T> {\n        #[doc = \"Create a new GreeterServer from a type that implements Greeter.\"]\n        pub fn new(inner: T) -> Self {\n            let inner = Arc::new(inner);\n            Self::from_shared(inner)\n        }\n        pub fn from_shared(inner: Arc<T>) -> Self {\n            Self { inner }\n        }\n    }\n    impl<T: Greeter> GreeterServerSvc<T> {\n        pub fn new(inner: Arc<T>) -> Self {\n            Self { inner }\n        }\n    }\n    impl<T: Greeter, R> Service<R> for GreeterServer<T> {\n        type Response = GreeterServerSvc<T>;\n        type Error = Never;\n        type Future = Ready<Result<Self::Response, Self::Error>>;\n        fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n        fn call(&mut self, _: R) -> Self::Future {\n            ok(GreeterServerSvc::new(self.inner.clone()))\n        }\n    }\n    impl<T: Greeter> Service<http::Request<HyperBody>> for GreeterServerSvc<T> {\n        type Response = http::Response<tonic::body::BoxBody>;\n        type Error = Never;\n        type Future = BoxFuture<Self::Response, Self::Error>;\n        fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n        fn call(&mut self, req: http::Request<HyperBody>) -> Self::Future {\n            let inner = self.inner.clone();\n            match req.uri().path() {\n                \"/helloworld.Greeter/SayHello\" => {\n                    struct SayHello<T: Greeter>(pub Arc<T>);\n                    impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest> for SayHello<T> {\n                        type Response = super::HelloReply;\n                        type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<super::HelloRequest>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move { inner.say_hello(request).await };\n                            Box::pin(fut)\n                        }\n                    }\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = SayHello(inner);\n                        let codec = tonic::codec::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec);\n                        let res = grpc.unary(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                _ => Box::pin(async move {\n                    Ok(http::Response::builder()\n                        .status(200)\n                        .header(\"grpc-status\", \"12\")\n                        .body(empty_body())\n                        .unwrap())\n                }),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tonic/benches-disabled/benchmarks/compiled_protos/mod.rs",
    "content": "pub mod diverse_types;\npub mod helloworld;\n"
  },
  {
    "path": "tonic/benches-disabled/benchmarks/mod.rs",
    "content": "pub mod request_response;\npub mod request_response_diverse_types;\n\npub mod compiled_protos;\nmod utils;\n"
  },
  {
    "path": "tonic/benches-disabled/benchmarks/request_response.rs",
    "content": "use criterion::*;\n\nuse crate::benchmarks::compiled_protos::helloworld::{HelloReply, HelloRequest};\nuse crate::benchmarks::utils;\n\nfn build_request(_name: String) {\n    let _request = tonic::Request::new(HelloRequest { name: _name });\n}\n\nfn build_response(_message: String) {\n    let _response = tonic::Request::new(HelloReply { message: _message });\n}\n\npub fn bench_throughput(c: &mut Criterion) {\n    let mut group = c.benchmark_group(\"Request_Response\");\n\n    let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);\n\n    group.plot_config(plot_config);\n\n    let tiny_string = utils::generate_rnd_string(100).unwrap();\n    let short_string = utils::generate_rnd_string(1_000).unwrap();\n    let medium_string = utils::generate_rnd_string(10_000).unwrap();\n    let big_string = utils::generate_rnd_string(100_000).unwrap();\n    let huge_string = utils::generate_rnd_string(1_000_000).unwrap();\n    let massive_string = utils::generate_rnd_string(10_000_000).unwrap();\n\n    for size in [\n        tiny_string,\n        short_string,\n        medium_string,\n        big_string,\n        huge_string,\n        massive_string,\n    ]\n    .iter()\n    {\n        group.throughput(Throughput::Bytes(size.len() as u64));\n\n        group.bench_with_input(BenchmarkId::new(\"request\", size.len()), size, |b, i| {\n            b.iter(|| build_request(i.to_string()))\n        });\n        group.bench_with_input(BenchmarkId::new(\"response\", size.len()), size, |b, i| {\n            b.iter(|| build_response(i.to_string()))\n        });\n    }\n    group.finish();\n}\n"
  },
  {
    "path": "tonic/benches-disabled/benchmarks/request_response_diverse_types.rs",
    "content": "use criterion::*;\n\nuse crate::benchmarks::compiled_protos::diverse_types::{GoogleMessage1, GoogleMessage1SubMessage};\nuse crate::benchmarks::utils;\n\nfn build_request(_name: String) {\n    let sub_message = GoogleMessage1SubMessage {\n        field1: 10,\n        field2: 20,\n        field3: 30,\n        field15: _name,\n        field12: false,\n        field13: 70,\n        field14: 80,\n        field16: 90,\n        field19: 100,\n        field20: true,\n        field28: false,\n        field21: 110,\n        field22: 120,\n        field23: false,\n        field206: true,\n        field203: 233,\n        field204: 333,\n        field205: String::from(\"idiopathic\"),\n        field207: 4000,\n        field300: 4000,\n    };\n\n    let _request = tonic::Request::new(GoogleMessage1 {\n        field1: String::from(\"foo\"),\n        field9: String::from(\"red\"),\n        field18: String::from(\"red\"),\n        field80: true,\n        field81: true,\n        field2: 10,\n        field3: 30,\n        field280: 28,\n        field6: 60,\n        field22: 220,\n        field4: String::from(\"red\"),\n        field5: Vec::new(),\n        field59: true,\n        field7: String::from(\"blue\"),\n        field16: 160,\n        field130: 13,\n        field17: false,\n        field12: true,\n        field13: true,\n        field14: false,\n        field104: 1040,\n        field100: 50,\n        field101: 1010,\n        field102: String::from(\"green\"),\n        field103: String::from(\"pink\"),\n        field29: 290,\n        field30: true,\n        field60: 601,\n        field271: 27,\n        field272: 200,\n        field150: 15,\n        field23: 230,\n        field24: false,\n        field25: 250,\n        field15: Some(sub_message),\n        field78: true,\n        field67: 670,\n        field68: 680,\n        field128: 1280,\n        field129: String::from(\"red\"),\n        field131: 300,\n    });\n}\n\npub fn bench_throughput(c: &mut Criterion) {\n    let mut group = c.benchmark_group(\"Request_Response_Diverse_Types\");\n\n    //log plot to get everything on the graph\n    let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);\n\n    group.plot_config(plot_config);\n\n    let tiny_string = utils::generate_rnd_string(100).unwrap();\n    let short_string = utils::generate_rnd_string(1_000).unwrap();\n    let medium_string = utils::generate_rnd_string(10_000).unwrap();\n\n    for size in [tiny_string, short_string, medium_string].iter() {\n        group.throughput(Throughput::Bytes(size.len() as u64));\n\n        group.bench_with_input(BenchmarkId::new(\"request\", size.len()), size, |b, i| {\n            b.iter(|| build_request(i.to_string()))\n        });\n    }\n    group.finish();\n}\n"
  },
  {
    "path": "tonic/benches-disabled/benchmarks/utils.rs",
    "content": "use rand::distributions::Alphanumeric;\nuse rand::{thread_rng, Rng};\n\npub fn generate_rnd_string(string_size: usize) -> Result<String, Box<dyn std::error::Error>> {\n    let rand_name: String = thread_rng()\n        .sample_iter(&Alphanumeric)\n        .take(string_size)\n        .collect();\n\n    Ok(rand_name)\n}\n"
  },
  {
    "path": "tonic/benches-disabled/proto/diverse_types/diverse_types.proto",
    "content": "// Benchmark messages for proto3.\n// Pinched from the protobuf benchmarks\n\nsyntax = \"proto3\";\n\npackage benchmarks.proto3;\noption java_package = \"com.google.protobuf.benchmarks\";\n\n// This is the default, but we specify it here explicitly.\noption optimize_for = SPEED;\n\noption cc_enable_arenas = true;\n\nmessage GoogleMessage1 {\n  string field1 = 1;\n  string field9 = 9;\n  string field18 = 18;\n  bool field80 = 80;\n  bool field81 = 81;\n  int32 field2 = 2;\n  int32 field3 = 3;\n  int32 field280 = 280;\n  int32 field6 = 6;\n  int64 field22 = 22;\n  string field4 = 4;\n  repeated fixed64 field5 = 5;\n  bool field59 = 59;\n  string field7 = 7;\n  int32 field16 = 16;\n  int32 field130 = 130;\n  bool field12 = 12;\n  bool field17 = 17;\n  bool field13 = 13;\n  bool field14 = 14;\n  int32 field104 = 104;\n  int32 field100 = 100;\n  int32 field101 = 101;\n  string field102 = 102;\n  string field103 = 103;\n  int32 field29 = 29;\n  bool field30 = 30;\n  int32 field60 = 60;\n  int32 field271 = 271;\n  int32 field272 = 272;\n  int32 field150 = 150;\n  int32 field23 = 23;\n  bool field24 = 24;\n  int32 field25 = 25;\n  GoogleMessage1SubMessage field15 = 15;\n  bool field78 = 78;\n  int32 field67 = 67;\n  int32 field68 = 68;\n  int32 field128 = 128;\n  string field129 = 129;\n  int32 field131 = 131;\n}\n\nmessage GoogleMessage1SubMessage {\n  int32 field1 = 1;\n  int32 field2 = 2;\n  int32 field3 = 3;\n  string field15 = 15;\n  bool field12 = 12;\n  int64 field13 = 13;\n  int64 field14 = 14;\n  int32 field16 = 16;\n  int32 field19 = 19;\n  bool field20  = 20;\n  bool field28 = 28;\n  fixed64 field21 = 21;\n  int32 field22 = 22;\n  bool field23 = 23;\n  bool field206 = 206;\n  fixed32 field203 = 203;\n  int32 field204 = 204;\n  string field205 = 205;\n  uint64 field207 = 207;\n  uint64 field300 = 300;\n}\n"
  },
  {
    "path": "tonic/benches-disabled/proto/helloworld/helloworld.proto",
    "content": "// Copyright 2015 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"io.grpc.examples.helloworld\";\noption java_outer_classname = \"HelloWorldProto\";\n\npackage helloworld;\n\n// The greeting service definition.\nservice Greeter {\n  // Sends a greeting\n  rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n// The request message containing the user's name.\nmessage HelloRequest {\n  string name = 1;\n}\n\n// The response message containing the greetings\nmessage HelloReply {\n  string message = 1;\n}\n"
  },
  {
    "path": "tonic/src/body.rs",
    "content": "//! HTTP specific body utilities.\n\nuse std::{pin::Pin, task::Poll};\n\nuse http_body_util::BodyExt as _;\n\n// A type erased HTTP body.\ntype BoxBody = http_body_util::combinators::UnsyncBoxBody<bytes::Bytes, crate::Status>;\n\n/// A body type used in `tonic`.\n#[derive(Debug)]\npub struct Body {\n    kind: Kind,\n}\n\n#[derive(Debug)]\nenum Kind {\n    Empty,\n    Wrap(BoxBody),\n}\n\nimpl Body {\n    fn from_kind(kind: Kind) -> Self {\n        Self { kind }\n    }\n\n    /// Create a new empty `Body`.\n    pub const fn empty() -> Self {\n        Self { kind: Kind::Empty }\n    }\n\n    /// Create a new `Body` from an existing `Body`.\n    pub fn new<B>(body: B) -> Self\n    where\n        B: http_body::Body<Data = bytes::Bytes> + Send + 'static,\n        B::Error: Into<crate::BoxError>,\n    {\n        if body.is_end_stream() {\n            return Self::empty();\n        }\n\n        let mut body = Some(body);\n\n        if let Some(body) = <dyn std::any::Any>::downcast_mut::<Option<Body>>(&mut body) {\n            return body.take().unwrap();\n        }\n\n        if let Some(body) = <dyn std::any::Any>::downcast_mut::<Option<BoxBody>>(&mut body) {\n            return Self::from_kind(Kind::Wrap(body.take().unwrap()));\n        }\n\n        let body = body\n            .unwrap()\n            .map_err(crate::Status::map_error)\n            .boxed_unsync();\n\n        Self::from_kind(Kind::Wrap(body))\n    }\n}\n\nimpl Default for Body {\n    fn default() -> Self {\n        Self::empty()\n    }\n}\n\nimpl http_body::Body for Body {\n    type Data = bytes::Bytes;\n    type Error = crate::Status;\n\n    fn poll_frame(\n        mut self: std::pin::Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n    ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {\n        match &mut self.kind {\n            Kind::Empty => Poll::Ready(None),\n            Kind::Wrap(body) => Pin::new(body).poll_frame(cx),\n        }\n    }\n\n    fn size_hint(&self) -> http_body::SizeHint {\n        match &self.kind {\n            Kind::Empty => http_body::SizeHint::with_exact(0),\n            Kind::Wrap(body) => body.size_hint(),\n        }\n    }\n\n    fn is_end_stream(&self) -> bool {\n        match &self.kind {\n            Kind::Empty => true,\n            Kind::Wrap(body) => body.is_end_stream(),\n        }\n    }\n}\n"
  },
  {
    "path": "tonic/src/client/grpc.rs",
    "content": "use crate::codec::EncodeBody;\nuse crate::codec::{CompressionEncoding, EnabledCompressionEncodings};\nuse crate::metadata::GRPC_CONTENT_TYPE;\nuse crate::{\n    Code, Request, Response, Status,\n    body::Body,\n    client::GrpcService,\n    codec::{Codec, Decoder, Streaming},\n    request::SanitizeHeaders,\n};\nuse http::{\n    header::{CONTENT_TYPE, HeaderValue, TE},\n    uri::{PathAndQuery, Uri},\n};\nuse http_body::Body as HttpBody;\nuse std::{fmt, future, pin::pin};\nuse tokio_stream::{Stream, StreamExt};\n\n/// A gRPC client dispatcher.\n///\n/// This will wrap some inner [`GrpcService`] and will encode/decode\n/// messages via the provided codec.\n///\n/// Each request method takes a [`Request`], a [`PathAndQuery`], and a\n/// [`Codec`]. The request contains the message to send via the\n/// [`Codec::encoder`]. The path determines the fully qualified path\n/// that will be append to the outgoing uri. The path must follow\n/// the conventions explained in the [gRPC protocol definition] under `Path →`. An\n/// example of this path could look like `/greeter.Greeter/SayHello`.\n///\n/// [gRPC protocol definition]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests\npub struct Grpc<T> {\n    inner: T,\n    config: GrpcConfig,\n}\n\nstruct GrpcConfig {\n    origin: Uri,\n    /// Which compression encodings does the client accept?\n    accept_compression_encodings: EnabledCompressionEncodings,\n    /// The compression encoding that will be applied to requests.\n    send_compression_encodings: Option<CompressionEncoding>,\n    /// Limits the maximum size of a decoded message.\n    max_decoding_message_size: Option<usize>,\n    /// Limits the maximum size of an encoded message.\n    max_encoding_message_size: Option<usize>,\n}\n\nimpl<T> Grpc<T> {\n    /// Creates a new gRPC client with the provided [`GrpcService`].\n    pub fn new(inner: T) -> Self {\n        Self::with_origin(inner, Uri::default())\n    }\n\n    /// Creates a new gRPC client with the provided [`GrpcService`] and `Uri`.\n    ///\n    /// The provided Uri will use only the scheme and authority parts as the\n    /// path_and_query portion will be set for each method.\n    pub fn with_origin(inner: T, origin: Uri) -> Self {\n        Self {\n            inner,\n            config: GrpcConfig {\n                origin,\n                send_compression_encodings: None,\n                accept_compression_encodings: EnabledCompressionEncodings::default(),\n                max_decoding_message_size: None,\n                max_encoding_message_size: None,\n            },\n        }\n    }\n\n    /// Compress requests with the provided encoding.\n    ///\n    /// Requires the server to accept the specified encoding, otherwise it might return an error.\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a client generated by tonic-build:\n    ///\n    /// ```rust\n    /// use tonic::transport::Channel;\n    /// # enum CompressionEncoding { Gzip }\n    /// # struct TestClient<T>(T);\n    /// # impl<T> TestClient<T> {\n    /// #     fn new(channel: T) -> Self { Self(channel) }\n    /// #     fn send_compressed(self, _: CompressionEncoding) -> Self { self }\n    /// # }\n    ///\n    /// # async {\n    /// let channel = Channel::builder(\"127.0.0.1:3000\".parse().unwrap())\n    ///     .connect()\n    ///     .await\n    ///     .unwrap();\n    ///\n    /// let client = TestClient::new(channel).send_compressed(CompressionEncoding::Gzip);\n    /// # };\n    /// ```\n    pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n        self.config.send_compression_encodings = Some(encoding);\n        self\n    }\n\n    /// Enable accepting compressed responses.\n    ///\n    /// Requires the server to also support sending compressed responses.\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a client generated by tonic-build:\n    ///\n    /// ```rust\n    /// use tonic::transport::Channel;\n    /// # enum CompressionEncoding { Gzip }\n    /// # struct TestClient<T>(T);\n    /// # impl<T> TestClient<T> {\n    /// #     fn new(channel: T) -> Self { Self(channel) }\n    /// #     fn accept_compressed(self, _: CompressionEncoding) -> Self { self }\n    /// # }\n    ///\n    /// # async {\n    /// let channel = Channel::builder(\"127.0.0.1:3000\".parse().unwrap())\n    ///     .connect()\n    ///     .await\n    ///     .unwrap();\n    ///\n    /// let client = TestClient::new(channel).accept_compressed(CompressionEncoding::Gzip);\n    /// # };\n    /// ```\n    pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n        self.config.accept_compression_encodings.enable(encoding);\n        self\n    }\n\n    /// Limits the maximum size of a decoded message.\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a client generated by tonic-build:\n    ///\n    /// ```rust\n    /// use tonic::transport::Channel;\n    /// # struct TestClient<T>(T);\n    /// # impl<T> TestClient<T> {\n    /// #     fn new(channel: T) -> Self { Self(channel) }\n    /// #     fn max_decoding_message_size(self, _: usize) -> Self { self }\n    /// # }\n    ///\n    /// # async {\n    /// let channel = Channel::builder(\"127.0.0.1:3000\".parse().unwrap())\n    ///     .connect()\n    ///     .await\n    ///     .unwrap();\n    ///\n    /// // Set the limit to 2MB, Defaults to 4MB.\n    /// let limit = 2 * 1024 * 1024;\n    /// let client = TestClient::new(channel).max_decoding_message_size(limit);\n    /// # };\n    /// ```\n    pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n        self.config.max_decoding_message_size = Some(limit);\n        self\n    }\n\n    /// Limits the maximum size of an encoded message.\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a client generated by tonic-build:\n    ///\n    /// ```rust\n    /// use tonic::transport::Channel;\n    /// # struct TestClient<T>(T);\n    /// # impl<T> TestClient<T> {\n    /// #     fn new(channel: T) -> Self { Self(channel) }\n    /// #     fn max_encoding_message_size(self, _: usize) -> Self { self }\n    /// # }\n    ///\n    /// # async {\n    /// let channel = Channel::builder(\"127.0.0.1:3000\".parse().unwrap())\n    ///     .connect()\n    ///     .await\n    ///     .unwrap();\n    ///\n    /// // Set the limit to 2MB, Defaults to `usize::MAX`.\n    /// let limit = 2 * 1024 * 1024;\n    /// let client = TestClient::new(channel).max_encoding_message_size(limit);\n    /// # };\n    /// ```\n    pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n        self.config.max_encoding_message_size = Some(limit);\n        self\n    }\n\n    /// Check if the inner [`GrpcService`] is able to accept a  new request.\n    ///\n    /// This will call [`GrpcService::poll_ready`] until it returns ready or\n    /// an error. If this returns ready the inner [`GrpcService`] is ready to\n    /// accept one more request.\n    pub async fn ready(&mut self) -> Result<(), T::Error>\n    where\n        T: GrpcService<Body>,\n    {\n        future::poll_fn(|cx| self.inner.poll_ready(cx)).await\n    }\n\n    /// Send a single unary gRPC request.\n    pub async fn unary<M1, M2, C>(\n        &mut self,\n        request: Request<M1>,\n        path: PathAndQuery,\n        codec: C,\n    ) -> Result<Response<M2>, Status>\n    where\n        T: GrpcService<Body>,\n        T::ResponseBody: HttpBody + Send + 'static,\n        <T::ResponseBody as HttpBody>::Error: Into<crate::BoxError>,\n        C: Codec<Encode = M1, Decode = M2>,\n        M1: Send + Sync + 'static,\n        M2: Send + Sync + 'static,\n    {\n        let request = request.map(|m| tokio_stream::once(m));\n        self.client_streaming(request, path, codec).await\n    }\n\n    /// Send a client side streaming gRPC request.\n    pub async fn client_streaming<S, M1, M2, C>(\n        &mut self,\n        request: Request<S>,\n        path: PathAndQuery,\n        codec: C,\n    ) -> Result<Response<M2>, Status>\n    where\n        T: GrpcService<Body>,\n        T::ResponseBody: HttpBody + Send + 'static,\n        <T::ResponseBody as HttpBody>::Error: Into<crate::BoxError>,\n        S: Stream<Item = M1> + Send + 'static,\n        C: Codec<Encode = M1, Decode = M2>,\n        M1: Send + Sync + 'static,\n        M2: Send + Sync + 'static,\n    {\n        let (mut parts, body, extensions) =\n            self.streaming(request, path, codec).await?.into_parts();\n\n        let mut body = pin!(body);\n\n        let message = body\n            .try_next()\n            .await\n            .map_err(|mut status| {\n                status.metadata_mut().merge(parts.clone());\n                status\n            })?\n            .ok_or_else(|| Status::internal(\"Missing response message.\"))?;\n\n        if let Some(trailers) = body.trailers().await? {\n            parts.merge(trailers);\n        }\n\n        Ok(Response::from_parts(parts, message, extensions))\n    }\n\n    /// Send a server side streaming gRPC request.\n    pub async fn server_streaming<M1, M2, C>(\n        &mut self,\n        request: Request<M1>,\n        path: PathAndQuery,\n        codec: C,\n    ) -> Result<Response<Streaming<M2>>, Status>\n    where\n        T: GrpcService<Body>,\n        T::ResponseBody: HttpBody + Send + 'static,\n        <T::ResponseBody as HttpBody>::Error: Into<crate::BoxError>,\n        C: Codec<Encode = M1, Decode = M2>,\n        M1: Send + Sync + 'static,\n        M2: Send + Sync + 'static,\n    {\n        let request = request.map(|m| tokio_stream::once(m));\n        self.streaming(request, path, codec).await\n    }\n\n    /// Send a bi-directional streaming gRPC request.\n    pub async fn streaming<S, M1, M2, C>(\n        &mut self,\n        request: Request<S>,\n        path: PathAndQuery,\n        mut codec: C,\n    ) -> Result<Response<Streaming<M2>>, Status>\n    where\n        T: GrpcService<Body>,\n        T::ResponseBody: HttpBody + Send + 'static,\n        <T::ResponseBody as HttpBody>::Error: Into<crate::BoxError>,\n        S: Stream<Item = M1> + Send + 'static,\n        C: Codec<Encode = M1, Decode = M2>,\n        M1: Send + Sync + 'static,\n        M2: Send + Sync + 'static,\n    {\n        let request = request\n            .map(|s| {\n                EncodeBody::new_client(\n                    codec.encoder(),\n                    s.map(Ok),\n                    self.config.send_compression_encodings,\n                    self.config.max_encoding_message_size,\n                )\n            })\n            .map(Body::new);\n\n        let request = self.config.prepare_request(request, path);\n\n        let response = self\n            .inner\n            .call(request)\n            .await\n            .map_err(Status::from_error_generic)?;\n\n        let decoder = codec.decoder();\n\n        self.create_response(decoder, response)\n    }\n\n    // Keeping this code in a separate function from Self::streaming lets functions that return the\n    // same output share the generated binary code\n    fn create_response<M2>(\n        &self,\n        decoder: impl Decoder<Item = M2, Error = Status> + Send + 'static,\n        response: http::Response<T::ResponseBody>,\n    ) -> Result<Response<Streaming<M2>>, Status>\n    where\n        T: GrpcService<Body>,\n        T::ResponseBody: HttpBody + Send + 'static,\n        <T::ResponseBody as HttpBody>::Error: Into<crate::BoxError>,\n    {\n        let encoding = CompressionEncoding::from_encoding_header(\n            response.headers(),\n            self.config.accept_compression_encodings,\n        )?;\n\n        let status_code = response.status();\n        let trailers_only_status = Status::from_header_map(response.headers());\n\n        // We do not need to check for trailers if the `grpc-status` header is present\n        // with a valid code.\n        let expect_additional_trailers = if let Some(status) = trailers_only_status {\n            if status.code() != Code::Ok {\n                return Err(status);\n            }\n\n            false\n        } else {\n            true\n        };\n\n        let response = response.map(|body| {\n            if expect_additional_trailers {\n                Streaming::new_response(\n                    decoder,\n                    body,\n                    status_code,\n                    encoding,\n                    self.config.max_decoding_message_size,\n                )\n            } else {\n                Streaming::new_empty(decoder, body)\n            }\n        });\n\n        Ok(Response::from_http(response))\n    }\n}\n\nimpl GrpcConfig {\n    fn prepare_request(&self, request: Request<Body>, path: PathAndQuery) -> http::Request<Body> {\n        let mut parts = self.origin.clone().into_parts();\n\n        match &parts.path_and_query {\n            Some(pnq) if pnq != \"/\" => {\n                parts.path_and_query = Some(\n                    format!(\"{}{}\", pnq.path(), path)\n                        .parse()\n                        .expect(\"must form valid path_and_query\"),\n                )\n            }\n            _ => {\n                parts.path_and_query = Some(path);\n            }\n        }\n\n        let uri = Uri::from_parts(parts).expect(\"path_and_query only is valid Uri\");\n\n        let mut request = request.into_http(\n            uri,\n            http::Method::POST,\n            http::Version::HTTP_2,\n            SanitizeHeaders::Yes,\n        );\n\n        // Add the gRPC related HTTP headers\n        request\n            .headers_mut()\n            .insert(TE, HeaderValue::from_static(\"trailers\"));\n\n        // Set the content type\n        request\n            .headers_mut()\n            .insert(CONTENT_TYPE, GRPC_CONTENT_TYPE);\n\n        #[cfg(any(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n        if let Some(encoding) = self.send_compression_encodings {\n            request.headers_mut().insert(\n                crate::codec::compression::ENCODING_HEADER,\n                encoding.into_header_value(),\n            );\n        }\n\n        if let Some(header_value) = self\n            .accept_compression_encodings\n            .into_accept_encoding_header_value()\n        {\n            request.headers_mut().insert(\n                crate::codec::compression::ACCEPT_ENCODING_HEADER,\n                header_value,\n            );\n        }\n\n        request\n    }\n}\n\nimpl<T: Clone> Clone for Grpc<T> {\n    fn clone(&self) -> Self {\n        Self {\n            inner: self.inner.clone(),\n            config: GrpcConfig {\n                origin: self.config.origin.clone(),\n                send_compression_encodings: self.config.send_compression_encodings,\n                accept_compression_encodings: self.config.accept_compression_encodings,\n                max_encoding_message_size: self.config.max_encoding_message_size,\n                max_decoding_message_size: self.config.max_decoding_message_size,\n            },\n        }\n    }\n}\n\nimpl<T: fmt::Debug> fmt::Debug for Grpc<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Grpc\")\n            .field(\"inner\", &self.inner)\n            .field(\"origin\", &self.config.origin)\n            .field(\n                \"compression_encoding\",\n                &self.config.send_compression_encodings,\n            )\n            .field(\n                \"accept_compression_encodings\",\n                &self.config.accept_compression_encodings,\n            )\n            .field(\n                \"max_decoding_message_size\",\n                &self.config.max_decoding_message_size,\n            )\n            .field(\n                \"max_encoding_message_size\",\n                &self.config.max_encoding_message_size,\n            )\n            .finish()\n    }\n}\n"
  },
  {
    "path": "tonic/src/client/mod.rs",
    "content": "//! Generic client implementation.\n//!\n//! This module contains the low level components to build a gRPC client. It\n//! provides a codec agnostic gRPC client dispatcher and a decorated tower\n//! service trait.\n//!\n//! This client is generally used by some code generation tool to provide stubs\n//! for the gRPC service. Thusly, they are a bit cumbersome to use by hand.\n//!\n//! ## Concurrent usage\n//!\n//! Upon using the your generated client, you will discover all the functions\n//! corresponding to your rpc methods take `&mut self`, making concurrent\n//! usage of the client difficult. The answer is simply to clone the client,\n//! which is cheap as all client instances will share the same channel for\n//! communication. For more details, see\n//! [transport::Channel](../transport/struct.Channel.html#multiplexing-requests).\n\nmod grpc;\nmod service;\n\npub use self::grpc::Grpc;\npub use self::service::GrpcService;\n"
  },
  {
    "path": "tonic/src/client/service.rs",
    "content": "use http_body::Body;\nuse std::future::Future;\nuse std::task::{Context, Poll};\nuse tower_service::Service;\n\n/// Definition of the gRPC trait alias for [`tower_service`].\n///\n/// This trait enforces that all tower services provided to [`Grpc`] implements\n/// the correct traits.\n///\n/// [`Grpc`]: ../client/struct.Grpc.html\n/// [`tower_service`]: https://docs.rs/tower-service\npub trait GrpcService<ReqBody> {\n    /// Responses body given by the service.\n    type ResponseBody: Body;\n    /// Errors produced by the service.\n    type Error: Into<crate::BoxError>;\n    /// The future response value.\n    type Future: Future<Output = Result<http::Response<Self::ResponseBody>, Self::Error>>;\n\n    /// Returns `Ready` when the service is able to process requests.\n    ///\n    /// Reference [`Service::poll_ready`].\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;\n\n    /// Process the request and return the response asynchronously.\n    ///\n    /// Reference [`Service::call`].\n    fn call(&mut self, request: http::Request<ReqBody>) -> Self::Future;\n}\n\nimpl<T, ReqBody, ResBody> GrpcService<ReqBody> for T\nwhere\n    T: Service<http::Request<ReqBody>, Response = http::Response<ResBody>>,\n    T::Error: Into<crate::BoxError>,\n    ResBody: Body,\n    <ResBody as Body>::Error: Into<crate::BoxError>,\n{\n    type ResponseBody = ResBody;\n    type Error = T::Error;\n    type Future = T::Future;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Service::poll_ready(self, cx)\n    }\n\n    fn call(&mut self, request: http::Request<ReqBody>) -> Self::Future {\n        Service::call(self, request)\n    }\n}\n"
  },
  {
    "path": "tonic/src/codec/buffer.rs",
    "content": "use bytes::buf::UninitSlice;\nuse bytes::{Buf, BufMut, Bytes, BytesMut};\n\n/// A specialized buffer to decode gRPC messages from.\n#[derive(Debug)]\npub struct DecodeBuf<'a> {\n    buf: &'a mut BytesMut,\n    len: usize,\n}\n\n/// A specialized buffer to encode gRPC messages into.\n#[derive(Debug)]\npub struct EncodeBuf<'a> {\n    buf: &'a mut BytesMut,\n}\n\nimpl<'a> DecodeBuf<'a> {\n    pub(crate) fn new(buf: &'a mut BytesMut, len: usize) -> Self {\n        DecodeBuf { buf, len }\n    }\n}\n\nimpl Buf for DecodeBuf<'_> {\n    #[inline]\n    fn remaining(&self) -> usize {\n        self.len\n    }\n\n    #[inline]\n    fn chunk(&self) -> &[u8] {\n        let ret = self.buf.chunk();\n\n        if ret.len() > self.len {\n            &ret[..self.len]\n        } else {\n            ret\n        }\n    }\n\n    #[inline]\n    fn advance(&mut self, cnt: usize) {\n        assert!(cnt <= self.len);\n        self.buf.advance(cnt);\n        self.len -= cnt;\n    }\n\n    #[inline]\n    fn copy_to_bytes(&mut self, len: usize) -> Bytes {\n        assert!(len <= self.len);\n        self.len -= len;\n        self.buf.copy_to_bytes(len)\n    }\n}\n\nimpl<'a> EncodeBuf<'a> {\n    pub(crate) fn new(buf: &'a mut BytesMut) -> Self {\n        EncodeBuf { buf }\n    }\n}\n\nimpl EncodeBuf<'_> {\n    /// Reserves capacity for at least `additional` more bytes to be inserted\n    /// into the buffer.\n    ///\n    /// More than `additional` bytes may be reserved in order to avoid frequent\n    /// reallocations. A call to `reserve` may result in an allocation.\n    #[inline]\n    pub fn reserve(&mut self, additional: usize) {\n        self.buf.reserve(additional);\n    }\n}\n\nunsafe impl BufMut for EncodeBuf<'_> {\n    #[inline]\n    fn remaining_mut(&self) -> usize {\n        self.buf.remaining_mut()\n    }\n\n    #[inline]\n    unsafe fn advance_mut(&mut self, cnt: usize) {\n        unsafe { self.buf.advance_mut(cnt) }\n    }\n\n    #[inline]\n    fn chunk_mut(&mut self) -> &mut UninitSlice {\n        self.buf.chunk_mut()\n    }\n\n    #[inline]\n    fn put<T: Buf>(&mut self, src: T)\n    where\n        Self: Sized,\n    {\n        self.buf.put(src)\n    }\n\n    #[inline]\n    fn put_slice(&mut self, src: &[u8]) {\n        self.buf.put_slice(src)\n    }\n\n    #[inline]\n    fn put_bytes(&mut self, val: u8, cnt: usize) {\n        self.buf.put_bytes(val, cnt);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn decode_buf() {\n        let mut payload = BytesMut::with_capacity(100);\n        payload.put(&vec![0u8; 50][..]);\n        let mut buf = DecodeBuf::new(&mut payload, 20);\n\n        assert_eq!(buf.len, 20);\n        assert_eq!(buf.remaining(), 20);\n        assert_eq!(buf.chunk().len(), 20);\n\n        buf.advance(10);\n        assert_eq!(buf.remaining(), 10);\n\n        let mut out = [0; 5];\n        buf.copy_to_slice(&mut out);\n        assert_eq!(buf.remaining(), 5);\n        assert_eq!(buf.chunk().len(), 5);\n\n        assert_eq!(buf.copy_to_bytes(5).len(), 5);\n        assert!(!buf.has_remaining());\n    }\n\n    #[test]\n    fn encode_buf() {\n        let mut bytes = BytesMut::with_capacity(100);\n        let mut buf = EncodeBuf::new(&mut bytes);\n\n        let initial = buf.remaining_mut();\n        unsafe { buf.advance_mut(20) };\n        assert_eq!(buf.remaining_mut(), initial - 20);\n\n        buf.put_u8(b'a');\n        assert_eq!(buf.remaining_mut(), initial - 20 - 1);\n    }\n}\n"
  },
  {
    "path": "tonic/src/codec/compression.rs",
    "content": "use crate::{Status, metadata::MetadataValue};\nuse bytes::{Buf, BufMut, BytesMut};\n#[cfg(feature = \"gzip\")]\nuse flate2::read::{GzDecoder, GzEncoder};\n#[cfg(feature = \"deflate\")]\nuse flate2::read::{ZlibDecoder, ZlibEncoder};\nuse std::{borrow::Cow, fmt};\n#[cfg(feature = \"zstd\")]\nuse zstd::stream::read::{Decoder, Encoder};\n\npub(crate) const ENCODING_HEADER: &str = \"grpc-encoding\";\npub(crate) const ACCEPT_ENCODING_HEADER: &str = \"grpc-accept-encoding\";\n\n/// Struct used to configure which encodings are enabled on a server or channel.\n///\n/// Represents an ordered list of compression encodings that are enabled.\n#[derive(Debug, Default, Clone, Copy)]\npub struct EnabledCompressionEncodings {\n    inner: [Option<CompressionEncoding>; 3],\n}\n\nimpl EnabledCompressionEncodings {\n    /// Enable a [`CompressionEncoding`].\n    ///\n    /// Adds the new encoding to the end of the encoding list.\n    pub fn enable(&mut self, encoding: CompressionEncoding) {\n        for e in self.inner.iter_mut() {\n            match e {\n                Some(e) if *e == encoding => return,\n                None => {\n                    *e = Some(encoding);\n                    return;\n                }\n                _ => continue,\n            }\n        }\n    }\n\n    /// Remove the last [`CompressionEncoding`].\n    pub fn pop(&mut self) -> Option<CompressionEncoding> {\n        self.inner\n            .iter_mut()\n            .rev()\n            .find(|entry| entry.is_some())?\n            .take()\n    }\n\n    pub(crate) fn into_accept_encoding_header_value(self) -> Option<http::HeaderValue> {\n        let mut value = BytesMut::new();\n        for encoding in self.inner.into_iter().flatten() {\n            value.put_slice(encoding.as_str().as_bytes());\n            value.put_u8(b',');\n        }\n\n        if value.is_empty() {\n            return None;\n        }\n\n        value.put_slice(b\"identity\");\n        Some(http::HeaderValue::from_maybe_shared(value).unwrap())\n    }\n\n    /// Check if a [`CompressionEncoding`] is enabled.\n    pub fn is_enabled(&self, encoding: CompressionEncoding) -> bool {\n        self.inner.contains(&Some(encoding))\n    }\n\n    /// Check if any [`CompressionEncoding`]s are enabled.\n    pub fn is_empty(&self) -> bool {\n        self.inner.iter().all(|e| e.is_none())\n    }\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub(crate) struct CompressionSettings {\n    pub(crate) encoding: CompressionEncoding,\n    /// buffer_growth_interval controls memory growth for internal buffers to balance resizing cost against memory waste.\n    /// The default buffer growth interval is 8 kilobytes.\n    pub(crate) buffer_growth_interval: usize,\n}\n\n/// The compression encodings Tonic supports.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\n#[non_exhaustive]\npub enum CompressionEncoding {\n    #[allow(missing_docs)]\n    #[cfg(feature = \"gzip\")]\n    Gzip,\n    #[allow(missing_docs)]\n    #[cfg(feature = \"deflate\")]\n    Deflate,\n    #[allow(missing_docs)]\n    #[cfg(feature = \"zstd\")]\n    Zstd,\n}\n\nimpl CompressionEncoding {\n    pub(crate) const ENCODINGS: &'static [CompressionEncoding] = &[\n        #[cfg(feature = \"gzip\")]\n        CompressionEncoding::Gzip,\n        #[cfg(feature = \"deflate\")]\n        CompressionEncoding::Deflate,\n        #[cfg(feature = \"zstd\")]\n        CompressionEncoding::Zstd,\n    ];\n\n    /// Based on the `grpc-accept-encoding` header, pick an encoding to use.\n    pub(crate) fn from_accept_encoding_header(\n        map: &http::HeaderMap,\n        enabled_encodings: EnabledCompressionEncodings,\n    ) -> Option<Self> {\n        if enabled_encodings.is_empty() {\n            return None;\n        }\n\n        let header_value = map.get(ACCEPT_ENCODING_HEADER)?;\n        let header_value_str = header_value.to_str().ok()?;\n\n        split_by_comma(header_value_str).find_map(|value| match value {\n            #[cfg(feature = \"gzip\")]\n            \"gzip\" => Some(CompressionEncoding::Gzip),\n            #[cfg(feature = \"deflate\")]\n            \"deflate\" => Some(CompressionEncoding::Deflate),\n            #[cfg(feature = \"zstd\")]\n            \"zstd\" => Some(CompressionEncoding::Zstd),\n            _ => None,\n        })\n    }\n\n    /// Get the value of `grpc-encoding` header. Returns an error if the encoding isn't supported.\n    pub(crate) fn from_encoding_header(\n        map: &http::HeaderMap,\n        enabled_encodings: EnabledCompressionEncodings,\n    ) -> Result<Option<Self>, Status> {\n        let Some(header_value) = map.get(ENCODING_HEADER) else {\n            return Ok(None);\n        };\n\n        match header_value.as_bytes() {\n            #[cfg(feature = \"gzip\")]\n            b\"gzip\" if enabled_encodings.is_enabled(CompressionEncoding::Gzip) => {\n                Ok(Some(CompressionEncoding::Gzip))\n            }\n            #[cfg(feature = \"deflate\")]\n            b\"deflate\" if enabled_encodings.is_enabled(CompressionEncoding::Deflate) => {\n                Ok(Some(CompressionEncoding::Deflate))\n            }\n            #[cfg(feature = \"zstd\")]\n            b\"zstd\" if enabled_encodings.is_enabled(CompressionEncoding::Zstd) => {\n                Ok(Some(CompressionEncoding::Zstd))\n            }\n            b\"identity\" => Ok(None),\n            other => {\n                let other = match std::str::from_utf8(other) {\n                    Ok(s) => Cow::Borrowed(s),\n                    Err(_) => Cow::Owned(format!(\"{other:?}\")),\n                };\n\n                let mut status = Status::unimplemented(format!(\n                    \"Content is compressed with `{other}` which isn't supported\"\n                ));\n\n                let header_value = enabled_encodings\n                    .into_accept_encoding_header_value()\n                    .map(MetadataValue::unchecked_from_header_value)\n                    .unwrap_or_else(|| MetadataValue::from_static(\"identity\"));\n                status\n                    .metadata_mut()\n                    .insert(ACCEPT_ENCODING_HEADER, header_value);\n\n                Err(status)\n            }\n        }\n    }\n\n    pub(crate) fn as_str(self) -> &'static str {\n        match self {\n            #[cfg(feature = \"gzip\")]\n            CompressionEncoding::Gzip => \"gzip\",\n            #[cfg(feature = \"deflate\")]\n            CompressionEncoding::Deflate => \"deflate\",\n            #[cfg(feature = \"zstd\")]\n            CompressionEncoding::Zstd => \"zstd\",\n        }\n    }\n\n    #[cfg(any(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n    pub(crate) fn into_header_value(self) -> http::HeaderValue {\n        http::HeaderValue::from_static(self.as_str())\n    }\n}\n\nimpl fmt::Display for CompressionEncoding {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.as_str())\n    }\n}\n\nfn split_by_comma(s: &str) -> impl Iterator<Item = &str> {\n    s.split(',').map(|s| s.trim())\n}\n\n/// Compress `len` bytes from `decompressed_buf` into `out_buf`.\n/// buffer_size_increment is a hint to control the growth of out_buf versus the cost of resizing it.\n#[allow(unused_variables, unreachable_code)]\npub(crate) fn compress(\n    settings: CompressionSettings,\n    decompressed_buf: &mut BytesMut,\n    out_buf: &mut BytesMut,\n    len: usize,\n) -> Result<(), std::io::Error> {\n    let buffer_growth_interval = settings.buffer_growth_interval;\n    let capacity = ((len / buffer_growth_interval) + 1) * buffer_growth_interval;\n    out_buf.reserve(capacity);\n\n    #[cfg(any(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n    let mut out_writer = out_buf.writer();\n\n    match settings.encoding {\n        #[cfg(feature = \"gzip\")]\n        CompressionEncoding::Gzip => {\n            let mut gzip_encoder = GzEncoder::new(\n                &decompressed_buf[0..len],\n                // FIXME: support customizing the compression level\n                flate2::Compression::new(6),\n            );\n            std::io::copy(&mut gzip_encoder, &mut out_writer)?;\n        }\n        #[cfg(feature = \"deflate\")]\n        CompressionEncoding::Deflate => {\n            let mut deflate_encoder = ZlibEncoder::new(\n                &decompressed_buf[0..len],\n                // FIXME: support customizing the compression level\n                flate2::Compression::new(6),\n            );\n            std::io::copy(&mut deflate_encoder, &mut out_writer)?;\n        }\n        #[cfg(feature = \"zstd\")]\n        CompressionEncoding::Zstd => {\n            let mut zstd_encoder = Encoder::new(\n                &decompressed_buf[0..len],\n                // FIXME: support customizing the compression level\n                zstd::DEFAULT_COMPRESSION_LEVEL,\n            )?;\n            std::io::copy(&mut zstd_encoder, &mut out_writer)?;\n        }\n    }\n\n    decompressed_buf.advance(len);\n\n    Ok(())\n}\n\n/// Decompress `len` bytes from `compressed_buf` into `out_buf`.\n#[allow(unused_variables, unreachable_code)]\npub(crate) fn decompress(\n    settings: CompressionSettings,\n    compressed_buf: &mut BytesMut,\n    mut out_buf: bytes::buf::Limit<&mut BytesMut>,\n    len: usize,\n) -> Result<(), std::io::Error> {\n    let buffer_growth_interval = settings.buffer_growth_interval;\n    let estimate_decompressed_len = len * 2;\n    let capacity = std::cmp::min(\n        bytes::buf::Limit::limit(&out_buf),\n        ((estimate_decompressed_len / buffer_growth_interval) + 1) * buffer_growth_interval,\n    );\n\n    out_buf.get_mut().reserve(capacity);\n\n    #[cfg(any(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n    let mut out_writer = out_buf.writer();\n\n    match settings.encoding {\n        #[cfg(feature = \"gzip\")]\n        CompressionEncoding::Gzip => {\n            let mut gzip_decoder = GzDecoder::new(&compressed_buf[0..len]);\n            std::io::copy(&mut gzip_decoder, &mut out_writer)?;\n        }\n        #[cfg(feature = \"deflate\")]\n        CompressionEncoding::Deflate => {\n            let mut deflate_decoder = ZlibDecoder::new(&compressed_buf[0..len]);\n            std::io::copy(&mut deflate_decoder, &mut out_writer)?;\n        }\n        #[cfg(feature = \"zstd\")]\n        CompressionEncoding::Zstd => {\n            let mut zstd_decoder = Decoder::new(&compressed_buf[0..len])?;\n            std::io::copy(&mut zstd_decoder, &mut out_writer)?;\n        }\n    }\n\n    compressed_buf.advance(len);\n\n    Ok(())\n}\n\n/// Controls compression behavior for individual messages within a stream.\n#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]\npub enum SingleMessageCompressionOverride {\n    /// Inherit whatever compression is already configured. If the stream is compressed this\n    /// message will also be configured.\n    ///\n    /// This is the default.\n    #[default]\n    Inherit,\n    /// Don't compress this message, even if compression is enabled on the stream.\n    Disable,\n}\n\n#[cfg(test)]\nmod tests {\n    #[cfg(any(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n    use http::HeaderValue;\n\n    use super::*;\n\n    #[test]\n    fn convert_none_into_header_value() {\n        let encodings = EnabledCompressionEncodings::default();\n\n        assert!(encodings.into_accept_encoding_header_value().is_none());\n    }\n\n    #[test]\n    #[cfg(feature = \"gzip\")]\n    fn convert_gzip_into_header_value() {\n        const GZIP: HeaderValue = HeaderValue::from_static(\"gzip,identity\");\n\n        let encodings = EnabledCompressionEncodings {\n            inner: [Some(CompressionEncoding::Gzip), None, None],\n        };\n\n        assert_eq!(encodings.into_accept_encoding_header_value().unwrap(), GZIP);\n\n        let encodings = EnabledCompressionEncodings {\n            inner: [None, None, Some(CompressionEncoding::Gzip)],\n        };\n\n        assert_eq!(encodings.into_accept_encoding_header_value().unwrap(), GZIP);\n    }\n\n    #[test]\n    #[cfg(feature = \"zstd\")]\n    fn convert_zstd_into_header_value() {\n        const ZSTD: HeaderValue = HeaderValue::from_static(\"zstd,identity\");\n\n        let encodings = EnabledCompressionEncodings {\n            inner: [Some(CompressionEncoding::Zstd), None, None],\n        };\n\n        assert_eq!(encodings.into_accept_encoding_header_value().unwrap(), ZSTD);\n\n        let encodings = EnabledCompressionEncodings {\n            inner: [None, None, Some(CompressionEncoding::Zstd)],\n        };\n\n        assert_eq!(encodings.into_accept_encoding_header_value().unwrap(), ZSTD);\n    }\n\n    #[test]\n    #[cfg(all(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n    fn convert_compression_encodings_into_header_value() {\n        let encodings = EnabledCompressionEncodings {\n            inner: [\n                Some(CompressionEncoding::Gzip),\n                Some(CompressionEncoding::Deflate),\n                Some(CompressionEncoding::Zstd),\n            ],\n        };\n\n        assert_eq!(\n            encodings.into_accept_encoding_header_value().unwrap(),\n            HeaderValue::from_static(\"gzip,deflate,zstd,identity\"),\n        );\n\n        let encodings = EnabledCompressionEncodings {\n            inner: [\n                Some(CompressionEncoding::Zstd),\n                Some(CompressionEncoding::Deflate),\n                Some(CompressionEncoding::Gzip),\n            ],\n        };\n\n        assert_eq!(\n            encodings.into_accept_encoding_header_value().unwrap(),\n            HeaderValue::from_static(\"zstd,deflate,gzip,identity\"),\n        );\n    }\n}\n"
  },
  {
    "path": "tonic/src/codec/decode.rs",
    "content": "use super::compression::{CompressionEncoding, CompressionSettings, decompress};\nuse super::{BufferSettings, DEFAULT_MAX_RECV_MESSAGE_SIZE, DecodeBuf, Decoder, HEADER_SIZE};\nuse crate::{Code, Status, body::Body, metadata::MetadataMap};\nuse bytes::{Buf, BufMut, BytesMut};\nuse http::{HeaderMap, StatusCode};\nuse http_body::Body as HttpBody;\nuse http_body_util::BodyExt;\nuse std::{\n    fmt, future,\n    pin::Pin,\n    task::ready,\n    task::{Context, Poll},\n};\nuse sync_wrapper::SyncWrapper;\nuse tokio_stream::Stream;\nuse tracing::{debug, trace};\n\n/// Streaming requests and responses.\n///\n/// This will wrap some inner [`Body`] and [`Decoder`] and provide an interface\n/// to fetch the message stream and trailing metadata\npub struct Streaming<T> {\n    decoder: SyncWrapper<Box<dyn Decoder<Item = T, Error = Status> + Send + 'static>>,\n    inner: StreamingInner,\n}\n\nstruct StreamingInner {\n    body: SyncWrapper<Body>,\n    state: State,\n    direction: Direction,\n    buf: BytesMut,\n    trailers: Option<HeaderMap>,\n    decompress_buf: BytesMut,\n    encoding: Option<CompressionEncoding>,\n    max_message_size: Option<usize>,\n}\n\nimpl<T> Unpin for Streaming<T> {}\n\n#[derive(Debug, Clone)]\nenum State {\n    ReadHeader,\n    ReadBody {\n        compression: Option<CompressionEncoding>,\n        len: usize,\n    },\n    Error(Option<Status>),\n}\n\n#[derive(Debug, PartialEq, Eq)]\nenum Direction {\n    Request,\n    Response(StatusCode),\n    EmptyResponse,\n}\n\nimpl<T> Streaming<T> {\n    /// Create a new streaming response in the grpc response format for decoding a response [Body]\n    /// into message of type T\n    pub fn new_response<B, D>(\n        decoder: D,\n        body: B,\n        status_code: StatusCode,\n        encoding: Option<CompressionEncoding>,\n        max_message_size: Option<usize>,\n    ) -> Self\n    where\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError>,\n        D: Decoder<Item = T, Error = Status> + Send + 'static,\n    {\n        Self::new(\n            decoder,\n            body,\n            Direction::Response(status_code),\n            encoding,\n            max_message_size,\n        )\n    }\n\n    /// Create empty response. For creating responses that have no content (headers + trailers only)\n    pub fn new_empty<B, D>(decoder: D, body: B) -> Self\n    where\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError>,\n        D: Decoder<Item = T, Error = Status> + Send + 'static,\n    {\n        Self::new(decoder, body, Direction::EmptyResponse, None, None)\n    }\n\n    /// Create a new streaming request in the grpc response format for decoding a request [Body]\n    /// into message of type T\n    pub fn new_request<B, D>(\n        decoder: D,\n        body: B,\n        encoding: Option<CompressionEncoding>,\n        max_message_size: Option<usize>,\n    ) -> Self\n    where\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError>,\n        D: Decoder<Item = T, Error = Status> + Send + 'static,\n    {\n        Self::new(\n            decoder,\n            body,\n            Direction::Request,\n            encoding,\n            max_message_size,\n        )\n    }\n\n    fn new<B, D>(\n        decoder: D,\n        body: B,\n        direction: Direction,\n        encoding: Option<CompressionEncoding>,\n        max_message_size: Option<usize>,\n    ) -> Self\n    where\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError>,\n        D: Decoder<Item = T, Error = Status> + Send + 'static,\n    {\n        let buffer_size = decoder.buffer_settings().buffer_size;\n        Self {\n            decoder: SyncWrapper::new(Box::new(decoder)),\n            inner: StreamingInner {\n                body: SyncWrapper::new(Body::new(\n                    body.map_frame(|frame| {\n                        frame.map_data(|mut buf| buf.copy_to_bytes(buf.remaining()))\n                    })\n                    .map_err(|err| Status::map_error(err.into())),\n                )),\n                state: State::ReadHeader,\n                direction,\n                buf: BytesMut::with_capacity(buffer_size),\n                trailers: None,\n                decompress_buf: BytesMut::new(),\n                encoding,\n                max_message_size,\n            },\n        }\n    }\n}\n\nimpl StreamingInner {\n    fn decode_chunk(\n        &mut self,\n        buffer_settings: BufferSettings,\n    ) -> Result<Option<DecodeBuf<'_>>, Status> {\n        if let State::ReadHeader = self.state {\n            if self.buf.remaining() < HEADER_SIZE {\n                return Ok(None);\n            }\n\n            let compression_encoding = match self.buf.get_u8() {\n                0 => None,\n                1 => {\n                    {\n                        if self.encoding.is_some() {\n                            self.encoding\n                        } else {\n                            // https://grpc.github.io/grpc/core/md_doc_compression.html\n                            // An ill-constructed message with its Compressed-Flag bit set but lacking a grpc-encoding\n                            // entry different from identity in its metadata MUST fail with INTERNAL status,\n                            // its associated description indicating the invalid Compressed-Flag condition.\n                            return Err(Status::internal(\n                                \"protocol error: received message with compressed-flag but no grpc-encoding was specified\",\n                            ));\n                        }\n                    }\n                }\n                f => {\n                    trace!(\"unexpected compression flag\");\n                    let message = if let Direction::Response(status) = self.direction {\n                        format!(\n                            \"protocol error: received message with invalid compression flag: {f} (valid flags are 0 and 1) while receiving response with status: {status}\"\n                        )\n                    } else {\n                        format!(\n                            \"protocol error: received message with invalid compression flag: {f} (valid flags are 0 and 1), while sending request\"\n                        )\n                    };\n                    return Err(Status::internal(message));\n                }\n            };\n\n            let len = self.buf.get_u32() as usize;\n            let limit = self\n                .max_message_size\n                .unwrap_or(DEFAULT_MAX_RECV_MESSAGE_SIZE);\n            if len > limit {\n                return Err(Status::out_of_range(format!(\n                    \"Error, decoded message length too large: found {len} bytes, the limit is: {limit} bytes\"\n                )));\n            }\n\n            self.buf.reserve(len);\n\n            self.state = State::ReadBody {\n                compression: compression_encoding,\n                len,\n            }\n        }\n\n        if let State::ReadBody { len, compression } = self.state {\n            // if we haven't read enough of the message then return and keep\n            // reading\n            if self.buf.remaining() < len || self.buf.len() < len {\n                return Ok(None);\n            }\n\n            let decode_buf = if let Some(encoding) = compression {\n                self.decompress_buf.clear();\n                let limit = self\n                    .max_message_size\n                    .unwrap_or(DEFAULT_MAX_RECV_MESSAGE_SIZE);\n                let limited_out_buf = (&mut self.decompress_buf).limit(limit);\n\n                if let Err(err) = decompress(\n                    CompressionSettings {\n                        encoding,\n                        buffer_growth_interval: buffer_settings.buffer_size,\n                    },\n                    &mut self.buf,\n                    limited_out_buf,\n                    len,\n                ) {\n                    if matches!(err.kind(), std::io::ErrorKind::WriteZero) {\n                        return Err(Status::resource_exhausted(format!(\n                            \"Error decompressing: size limit, of {limit} bytes, exceeded while decompressing message\"\n                        )));\n                    }\n                    let message = if let Direction::Response(status) = self.direction {\n                        format!(\n                            \"Error decompressing: {err}, while receiving response with status: {status}\"\n                        )\n                    } else {\n                        format!(\"Error decompressing: {err}, while sending request\")\n                    };\n                    return Err(Status::internal(message));\n                }\n                let decompressed_len = self.decompress_buf.len();\n                DecodeBuf::new(&mut self.decompress_buf, decompressed_len)\n            } else {\n                DecodeBuf::new(&mut self.buf, len)\n            };\n\n            return Ok(Some(decode_buf));\n        }\n\n        Ok(None)\n    }\n\n    // Returns Some(()) if data was found or None if the loop in `poll_next` should break\n    fn poll_frame(&mut self, cx: &mut Context<'_>) -> Poll<Result<Option<()>, Status>> {\n        let frame = match ready!(Pin::new(self.body.get_mut()).poll_frame(cx)) {\n            Some(Ok(frame)) => frame,\n            Some(Err(status)) => {\n                if self.direction == Direction::Request && status.code() == Code::Cancelled {\n                    return Poll::Ready(Ok(None));\n                }\n\n                let _ = std::mem::replace(&mut self.state, State::Error(Some(status.clone())));\n                debug!(\"decoder inner stream error: {:?}\", status);\n                return Poll::Ready(Err(status));\n            }\n            None => {\n                // FIXME: improve buf usage.\n                return Poll::Ready(if self.buf.has_remaining() {\n                    trace!(\"unexpected EOF decoding stream, state: {:?}\", self.state);\n                    Err(Status::internal(\"Unexpected EOF decoding stream.\"))\n                } else {\n                    Ok(None)\n                });\n            }\n        };\n\n        Poll::Ready(if frame.is_data() {\n            self.buf.put(frame.into_data().unwrap());\n            Ok(Some(()))\n        } else if frame.is_trailers() {\n            if let Some(trailers) = &mut self.trailers {\n                trailers.extend(frame.into_trailers().unwrap());\n            } else {\n                self.trailers = Some(frame.into_trailers().unwrap());\n            }\n\n            Ok(None)\n        } else {\n            panic!(\"unexpected frame: {frame:?}\");\n        })\n    }\n\n    fn response(&mut self) -> Result<(), Status> {\n        if let Direction::Response(status) = self.direction {\n            if let Err(Some(e)) = crate::status::infer_grpc_status(self.trailers.as_ref(), status) {\n                // If the trailers contain a grpc-status, then we should return that as the error\n                // and otherwise stop the stream (by taking the error state)\n                self.trailers.take();\n                return Err(e);\n            }\n        }\n        Ok(())\n    }\n}\n\nimpl<T> Streaming<T> {\n    /// Fetch the next message from this stream.\n    ///\n    /// # Return value\n    ///\n    /// - `Result::Err(val)` means a gRPC error was sent by the sender instead\n    ///   of a valid response message. Refer to [`Status::code`] and\n    ///   [`Status::message`] to examine possible error causes.\n    ///\n    /// - `Result::Ok(None)` means the stream was closed by the sender and no\n    ///   more messages will be delivered. Further attempts to call\n    ///   [`Streaming::message`] will result in the same return value.\n    ///\n    /// - `Result::Ok(Some(val))` means the sender streamed a valid response\n    ///   message `val`.\n    ///\n    /// ```rust\n    /// # use tonic::{Streaming, Status, codec::Decoder};\n    /// # use std::fmt::Debug;\n    /// # async fn next_message_ex<T, D>(mut request: Streaming<T>) -> Result<(), Status>\n    /// # where T: Debug,\n    /// # D: Decoder<Item = T, Error = Status> + Send  + 'static,\n    /// # {\n    /// if let Some(next_message) = request.message().await? {\n    ///     println!(\"{:?}\", next_message);\n    /// }\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn message(&mut self) -> Result<Option<T>, Status> {\n        match future::poll_fn(|cx| Pin::new(&mut *self).poll_next(cx)).await {\n            Some(Ok(m)) => Ok(Some(m)),\n            Some(Err(e)) => Err(e),\n            None => Ok(None),\n        }\n    }\n\n    /// Fetch the trailing metadata.\n    ///\n    /// This will drain the stream of all its messages to receive the trailing\n    /// metadata. If [`Streaming::message`] returns `None` then this function\n    /// will not need to poll for trailers since the body was totally consumed.\n    ///\n    /// ```rust\n    /// # use tonic::{Streaming, Status};\n    /// # async fn trailers_ex<T>(mut request: Streaming<T>) -> Result<(), Status> {\n    /// if let Some(metadata) = request.trailers().await? {\n    ///     println!(\"{:?}\", metadata);\n    /// }\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn trailers(&mut self) -> Result<Option<MetadataMap>, Status> {\n        // Shortcut to see if we already pulled the trailers in the stream step\n        // we need to do that so that the stream can error on trailing grpc-status\n        if let Some(trailers) = self.inner.trailers.take() {\n            return Ok(Some(MetadataMap::from_headers(trailers)));\n        }\n\n        // To fetch the trailers we must clear the body and drop it.\n        while self.message().await?.is_some() {}\n\n        // Since we call poll_trailers internally on poll_next we need to\n        // check if it got cached again.\n        if let Some(trailers) = self.inner.trailers.take() {\n            return Ok(Some(MetadataMap::from_headers(trailers)));\n        }\n\n        // We've polled through all the frames, and still no trailers, return None\n        Ok(None)\n    }\n\n    fn decode_chunk(&mut self) -> Result<Option<T>, Status> {\n        match self\n            .inner\n            .decode_chunk(self.decoder.get_mut().buffer_settings())?\n        {\n            Some(mut decode_buf) => match self.decoder.get_mut().decode(&mut decode_buf)? {\n                Some(msg) => {\n                    self.inner.state = State::ReadHeader;\n                    Ok(Some(msg))\n                }\n                None => Ok(None),\n            },\n            None => Ok(None),\n        }\n    }\n}\n\nimpl<T> Stream for Streaming<T> {\n    type Item = Result<T, Status>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        loop {\n            // When the stream encounters an error yield that error once and then on subsequent\n            // calls to poll_next return Poll::Ready(None) indicating that the stream has been\n            // fully exhausted.\n            if let State::Error(status) = &mut self.inner.state {\n                return Poll::Ready(status.take().map(Err));\n            }\n\n            if let Some(item) = self.decode_chunk()? {\n                return Poll::Ready(Some(Ok(item)));\n            }\n\n            if ready!(self.inner.poll_frame(cx))?.is_none() {\n                match self.inner.response() {\n                    Ok(()) => return Poll::Ready(None),\n                    Err(err) => self.inner.state = State::Error(Some(err)),\n                }\n            }\n        }\n    }\n}\n\nimpl<T> fmt::Debug for Streaming<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Streaming\").finish()\n    }\n}\n\n#[cfg(test)]\nstatic_assertions::assert_impl_all!(Streaming<()>: Send, Sync);\n"
  },
  {
    "path": "tonic/src/codec/encode.rs",
    "content": "use super::compression::{\n    CompressionEncoding, CompressionSettings, SingleMessageCompressionOverride, compress,\n};\nuse super::{BufferSettings, DEFAULT_MAX_SEND_MESSAGE_SIZE, EncodeBuf, Encoder, HEADER_SIZE};\nuse crate::Status;\nuse bytes::{BufMut, Bytes, BytesMut};\nuse http::HeaderMap;\nuse http_body::{Body, Frame};\nuse pin_project::pin_project;\nuse std::{\n    pin::Pin,\n    task::{Context, Poll, ready},\n};\nuse tokio_stream::{Stream, StreamExt, adapters::Fuse};\n\n/// Combinator for efficient encoding of messages into reasonably sized buffers.\n/// EncodedBytes encodes ready messages from its delegate stream into a BytesMut,\n/// splitting off and yielding a buffer when either:\n///  * The delegate stream polls as not ready, or\n///  * The encoded buffer surpasses YIELD_THRESHOLD.\n#[pin_project(project = EncodedBytesProj)]\n#[derive(Debug)]\nstruct EncodedBytes<T, U> {\n    #[pin]\n    source: Fuse<U>,\n    encoder: T,\n    compression_encoding: Option<CompressionEncoding>,\n    max_message_size: Option<usize>,\n    buf: BytesMut,\n    uncompression_buf: BytesMut,\n    error: Option<Status>,\n}\n\nimpl<T: Encoder, U: Stream> EncodedBytes<T, U> {\n    fn new(\n        encoder: T,\n        source: U,\n        compression_encoding: Option<CompressionEncoding>,\n        compression_override: SingleMessageCompressionOverride,\n        max_message_size: Option<usize>,\n    ) -> Self {\n        let buffer_settings = encoder.buffer_settings();\n        let buf = BytesMut::with_capacity(buffer_settings.buffer_size);\n\n        let compression_encoding =\n            if compression_override == SingleMessageCompressionOverride::Disable {\n                None\n            } else {\n                compression_encoding\n            };\n\n        let uncompression_buf = if compression_encoding.is_some() {\n            BytesMut::with_capacity(buffer_settings.buffer_size)\n        } else {\n            BytesMut::new()\n        };\n\n        Self {\n            source: source.fuse(),\n            encoder,\n            compression_encoding,\n            max_message_size,\n            buf,\n            uncompression_buf,\n            error: None,\n        }\n    }\n}\n\nimpl<T, U> Stream for EncodedBytes<T, U>\nwhere\n    T: Encoder<Error = Status>,\n    U: Stream<Item = Result<T::Item, Status>>,\n{\n    type Item = Result<Bytes, Status>;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let EncodedBytesProj {\n            mut source,\n            encoder,\n            compression_encoding,\n            max_message_size,\n            buf,\n            uncompression_buf,\n            error,\n        } = self.project();\n        let buffer_settings = encoder.buffer_settings();\n\n        if let Some(status) = error.take() {\n            return Poll::Ready(Some(Err(status)));\n        }\n\n        loop {\n            match source.as_mut().poll_next(cx) {\n                Poll::Pending if buf.is_empty() => {\n                    return Poll::Pending;\n                }\n                Poll::Ready(None) if buf.is_empty() => {\n                    return Poll::Ready(None);\n                }\n                Poll::Pending | Poll::Ready(None) => {\n                    return Poll::Ready(Some(Ok(buf.split_to(buf.len()).freeze())));\n                }\n                Poll::Ready(Some(Ok(item))) => {\n                    if let Err(status) = encode_item(\n                        encoder,\n                        buf,\n                        uncompression_buf,\n                        *compression_encoding,\n                        *max_message_size,\n                        buffer_settings,\n                        item,\n                    ) {\n                        return Poll::Ready(Some(Err(status)));\n                    }\n\n                    if buf.len() >= buffer_settings.yield_threshold {\n                        return Poll::Ready(Some(Ok(buf.split_to(buf.len()).freeze())));\n                    }\n                }\n                Poll::Ready(Some(Err(status))) => {\n                    if buf.is_empty() {\n                        return Poll::Ready(Some(Err(status)));\n                    }\n                    *error = Some(status);\n                    return Poll::Ready(Some(Ok(buf.split_to(buf.len()).freeze())));\n                }\n            }\n        }\n    }\n}\n\nfn encode_item<T>(\n    encoder: &mut T,\n    buf: &mut BytesMut,\n    uncompression_buf: &mut BytesMut,\n    compression_encoding: Option<CompressionEncoding>,\n    max_message_size: Option<usize>,\n    buffer_settings: BufferSettings,\n    item: T::Item,\n) -> Result<(), Status>\nwhere\n    T: Encoder<Error = Status>,\n{\n    let offset = buf.len();\n\n    buf.reserve(HEADER_SIZE);\n    unsafe {\n        buf.advance_mut(HEADER_SIZE);\n    }\n\n    if let Some(encoding) = compression_encoding {\n        uncompression_buf.clear();\n\n        encoder\n            .encode(item, &mut EncodeBuf::new(uncompression_buf))\n            .map_err(|err| Status::internal(format!(\"Error encoding: {err}\")))?;\n\n        let uncompressed_len = uncompression_buf.len();\n\n        compress(\n            CompressionSettings {\n                encoding,\n                buffer_growth_interval: buffer_settings.buffer_size,\n            },\n            uncompression_buf,\n            buf,\n            uncompressed_len,\n        )\n        .map_err(|err| Status::internal(format!(\"Error compressing: {err}\")))?;\n    } else {\n        encoder\n            .encode(item, &mut EncodeBuf::new(buf))\n            .map_err(|err| Status::internal(format!(\"Error encoding: {err}\")))?;\n    }\n\n    // now that we know length, we can write the header\n    finish_encoding(compression_encoding, max_message_size, &mut buf[offset..])\n}\n\nfn finish_encoding(\n    compression_encoding: Option<CompressionEncoding>,\n    max_message_size: Option<usize>,\n    buf: &mut [u8],\n) -> Result<(), Status> {\n    let len = buf.len() - HEADER_SIZE;\n    let limit = max_message_size.unwrap_or(DEFAULT_MAX_SEND_MESSAGE_SIZE);\n    if len > limit {\n        return Err(Status::out_of_range(format!(\n            \"Error, encoded message length too large: found {len} bytes, the limit is: {limit} bytes\"\n        )));\n    }\n\n    if len > u32::MAX as usize {\n        return Err(Status::resource_exhausted(format!(\n            \"Cannot return body with more than 4GB of data but got {len} bytes\"\n        )));\n    }\n    {\n        let mut buf = &mut buf[..HEADER_SIZE];\n        buf.put_u8(compression_encoding.is_some() as u8);\n        buf.put_u32(len as u32);\n    }\n\n    Ok(())\n}\n\n#[derive(Debug)]\nenum Role {\n    Client,\n    Server,\n}\n\n/// A specialized implementation of [Body] for encoding [Result<Bytes, Status>].\n#[pin_project]\n#[derive(Debug)]\npub struct EncodeBody<T, U> {\n    #[pin]\n    inner: EncodedBytes<T, U>,\n    state: EncodeState,\n}\n\n#[derive(Debug)]\nstruct EncodeState {\n    error: Option<Status>,\n    role: Role,\n    is_end_stream: bool,\n}\n\nimpl<T: Encoder, U: Stream> EncodeBody<T, U> {\n    /// Turns a stream of grpc messages into [EncodeBody] which is used by grpc clients for\n    /// turning the messages into http frames for sending over the network.\n    pub fn new_client(\n        encoder: T,\n        source: U,\n        compression_encoding: Option<CompressionEncoding>,\n        max_message_size: Option<usize>,\n    ) -> Self {\n        Self {\n            inner: EncodedBytes::new(\n                encoder,\n                source,\n                compression_encoding,\n                SingleMessageCompressionOverride::default(),\n                max_message_size,\n            ),\n            state: EncodeState {\n                error: None,\n                role: Role::Client,\n                is_end_stream: false,\n            },\n        }\n    }\n\n    /// Turns a stream of grpc results (message or error status) into [EncodeBody] which is used by grpc\n    /// servers for turning the messages into http frames for sending over the network.\n    pub fn new_server(\n        encoder: T,\n        source: U,\n        compression_encoding: Option<CompressionEncoding>,\n        compression_override: SingleMessageCompressionOverride,\n        max_message_size: Option<usize>,\n    ) -> Self {\n        Self {\n            inner: EncodedBytes::new(\n                encoder,\n                source,\n                compression_encoding,\n                compression_override,\n                max_message_size,\n            ),\n            state: EncodeState {\n                error: None,\n                role: Role::Server,\n                is_end_stream: false,\n            },\n        }\n    }\n}\n\nimpl EncodeState {\n    fn trailers(&mut self) -> Option<Result<HeaderMap, Status>> {\n        match self.role {\n            Role::Client => None,\n            Role::Server => {\n                if self.is_end_stream {\n                    return None;\n                }\n\n                self.is_end_stream = true;\n                let status = if let Some(status) = self.error.take() {\n                    status\n                } else {\n                    Status::ok(\"\")\n                };\n                Some(status.to_header_map())\n            }\n        }\n    }\n}\n\nimpl<T, U> Body for EncodeBody<T, U>\nwhere\n    T: Encoder<Error = Status>,\n    U: Stream<Item = Result<T::Item, Status>>,\n{\n    type Data = Bytes;\n    type Error = Status;\n\n    fn is_end_stream(&self) -> bool {\n        self.state.is_end_stream\n    }\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        let self_proj = self.project();\n        match ready!(self_proj.inner.poll_next(cx)) {\n            Some(Ok(d)) => Some(Ok(Frame::data(d))).into(),\n            Some(Err(status)) => match self_proj.state.role {\n                Role::Client => Some(Err(status)).into(),\n                Role::Server => {\n                    self_proj.state.is_end_stream = true;\n                    Some(Ok(Frame::trailers(status.to_header_map()?))).into()\n                }\n            },\n            None => self_proj\n                .state\n                .trailers()\n                .map(|t| t.map(Frame::trailers))\n                .into(),\n        }\n    }\n}\n"
  },
  {
    "path": "tonic/src/codec/mod.rs",
    "content": "//! Generic encoding and decoding.\n//!\n//! This module contains the generic `Codec`, `Encoder` and `Decoder` traits.\n\nmod buffer;\npub(crate) mod compression;\nmod decode;\nmod encode;\nuse crate::Status;\nuse std::io;\n\npub use self::buffer::{DecodeBuf, EncodeBuf};\npub use self::compression::{CompressionEncoding, EnabledCompressionEncodings};\npub use self::decode::Streaming;\npub use self::encode::EncodeBody;\n\n// Doc hidden since this is used in a test in another crate, we can expose this publically later\n// if we need it.\n#[doc(hidden)]\npub use self::compression::SingleMessageCompressionOverride;\n\n/// Unless overridden, this is the buffer size used for encoding requests.\n/// This is spent per-rpc, so you may wish to adjust it. The default is\n/// pretty good for most uses, but if you have a ton of concurrent rpcs\n/// you may find it too expensive.\nconst DEFAULT_CODEC_BUFFER_SIZE: usize = 8 * 1024;\nconst DEFAULT_YIELD_THRESHOLD: usize = 32 * 1024;\n\n/// Settings for how tonic allocates and grows buffers.\n///\n/// Tonic eagerly allocates the buffer_size per RPC, and grows\n/// the buffer by buffer_size increments to handle larger messages.\n/// Buffer size defaults to 8KiB.\n///\n/// Example:\n/// ```ignore\n/// Buffer start:       | 8kb |\n/// Message received:   |   24612 bytes    |\n/// Buffer grows:       | 8kb | 8kb | 8kb | 8kb |\n/// ```\n///\n/// The buffer grows to the next largest buffer_size increment of\n/// 32768 to hold 24612 bytes, which is just slightly too large for\n/// the previous buffer increment of 24576.\n///\n/// If you use a smaller buffer size you will waste less memory, but\n/// you will allocate more frequently. If one way or the other matters\n/// more to you, you may wish to customize your tonic Codec (see\n/// codec_buffers example).\n///\n/// Yield threshold is an optimization for streaming rpcs. Sometimes\n/// you may have many small messages ready to send. When they are ready,\n/// it is a much more efficient use of system resources to batch them\n/// together into one larger send(). The yield threshold controls how\n/// much you want to bulk up such a batch of ready-to-send messages.\n/// The larger your yield threshold the more you will batch - and\n/// consequently allocate contiguous memory, which might be relevant\n/// if you're considering large numbers here.\n/// If your server streaming rpc does not reach the yield threshold\n/// before it reaches Poll::Pending (meaning, it's waiting for more\n/// data from wherever you're streaming from) then Tonic will just send\n/// along a smaller batch. Yield threshold is an upper-bound, it will\n/// not affect the responsiveness of your streaming rpc (for reasonable\n/// sizes of yield threshold).\n/// Yield threshold defaults to 32 KiB.\n#[derive(Clone, Copy, Debug)]\npub struct BufferSettings {\n    buffer_size: usize,\n    yield_threshold: usize,\n}\n\nimpl BufferSettings {\n    /// Create a new `BufferSettings`\n    pub fn new(buffer_size: usize, yield_threshold: usize) -> Self {\n        Self {\n            buffer_size,\n            yield_threshold,\n        }\n    }\n}\n\nimpl Default for BufferSettings {\n    fn default() -> Self {\n        Self {\n            buffer_size: DEFAULT_CODEC_BUFFER_SIZE,\n            yield_threshold: DEFAULT_YIELD_THRESHOLD,\n        }\n    }\n}\n\n// Doc hidden because it's used in tests in another crate but not part of the\n// public api.\n#[doc(hidden)]\npub const HEADER_SIZE: usize =\n    // compression flag\n    std::mem::size_of::<u8>() +\n    // data length\n    std::mem::size_of::<u32>();\n\n// The default maximum uncompressed size in bytes for a message. Defaults to 4MB.\nconst DEFAULT_MAX_RECV_MESSAGE_SIZE: usize = 4 * 1024 * 1024;\nconst DEFAULT_MAX_SEND_MESSAGE_SIZE: usize = usize::MAX;\n\n/// Trait that knows how to encode and decode gRPC messages.\npub trait Codec {\n    /// The encodable message.\n    type Encode: Send + 'static;\n    /// The decodable message.\n    type Decode: Send + 'static;\n\n    /// The encoder that can encode a message.\n    type Encoder: Encoder<Item = Self::Encode, Error = Status> + Send + 'static;\n    /// The decoder that can decode a message.\n    type Decoder: Decoder<Item = Self::Decode, Error = Status> + Send + 'static;\n\n    /// Fetch the encoder.\n    fn encoder(&mut self) -> Self::Encoder;\n    /// Fetch the decoder.\n    fn decoder(&mut self) -> Self::Decoder;\n}\n\n/// Encodes gRPC message types\npub trait Encoder {\n    /// The type that is encoded.\n    type Item;\n\n    /// The type of encoding errors.\n    ///\n    /// The type of unrecoverable frame encoding errors.\n    type Error: From<io::Error>;\n\n    /// Encodes a message into the provided buffer.\n    fn encode(&mut self, item: Self::Item, dst: &mut EncodeBuf<'_>) -> Result<(), Self::Error>;\n\n    /// Controls how tonic creates and expands encode buffers.\n    fn buffer_settings(&self) -> BufferSettings {\n        BufferSettings::default()\n    }\n}\n\n/// Decodes gRPC message types\npub trait Decoder {\n    /// The type that is decoded.\n    type Item;\n\n    /// The type of unrecoverable frame decoding errors.\n    type Error: From<io::Error>;\n\n    /// Decode a message from the buffer.\n    ///\n    /// The buffer will contain exactly the bytes of a full message. There\n    /// is no need to get the length from the bytes, gRPC framing is handled\n    /// for you.\n    fn decode(&mut self, src: &mut DecodeBuf<'_>) -> Result<Option<Self::Item>, Self::Error>;\n\n    /// Controls how tonic creates and expands decode buffers.\n    fn buffer_settings(&self) -> BufferSettings {\n        BufferSettings::default()\n    }\n}\n"
  },
  {
    "path": "tonic/src/codegen.rs",
    "content": "//! Codegen exports used by `tonic-build`.\n\npub use async_trait::async_trait;\npub use tokio_stream;\n\npub use std::future::Future;\npub use std::pin::Pin;\npub use std::sync::Arc;\npub use std::task::{Context, Poll};\npub use tower_service::Service;\npub type StdError = Box<dyn std::error::Error + Send + Sync + 'static>;\npub use crate::codec::{CompressionEncoding, EnabledCompressionEncodings};\npub use crate::extensions::GrpcMethod;\npub use crate::service::interceptor::InterceptedService;\npub use bytes::Bytes;\npub use http;\npub use http_body::Body;\n\npub type BoxFuture<T, E> = self::Pin<Box<dyn self::Future<Output = Result<T, E>> + Send + 'static>>;\npub type BoxStream<T> =\n    self::Pin<Box<dyn tokio_stream::Stream<Item = Result<T, crate::Status>> + Send + 'static>>;\n"
  },
  {
    "path": "tonic/src/extensions.rs",
    "content": "/// A gRPC Method info extension.\n#[derive(Debug, Clone)]\npub struct GrpcMethod<'a> {\n    service: &'a str,\n    method: &'a str,\n}\n\nimpl<'a> GrpcMethod<'a> {\n    /// Create a new `GrpcMethod` extension.\n    #[doc(hidden)]\n    pub fn new(service: &'a str, method: &'a str) -> Self {\n        Self { service, method }\n    }\n\n    /// gRPC service name\n    pub fn service(&self) -> &str {\n        self.service\n    }\n    /// gRPC method name\n    pub fn method(&self) -> &str {\n        self.method\n    }\n}\n"
  },
  {
    "path": "tonic/src/lib.rs",
    "content": "//! A Rust implementation of [gRPC], a high performance, open source, general\n//! RPC framework that puts mobile and HTTP/2 first.\n//!\n//! [`tonic`] is a gRPC over HTTP/2 implementation focused on **high\n//! performance**, **interoperability**, and **flexibility**. This library was\n//! created to have first class support of async/await and to act as a core building\n//! block for production systems written in Rust.\n//!\n//! # Examples\n//!\n//! Examples can be found in the [`tonic-examples`] crate.\n//!\n//! # Getting Started\n//!\n//! Follow the instructions in the [`tonic-build`] crate documentation.\n//!\n//! # Feature Flags\n//!\n//! - `transport`: Enables the fully featured, batteries included client and server\n//!   implementation based on [`hyper`], [`tower`] and [`tokio`]. This enables `server`\n//!   and `channel` features. Enabled by default.\n//! - `server`: Enables just the full featured server portion of the `transport` feature.\n//! - `channel`: Enables just the full featured channel portion of the `transport` feature.\n//! - `router`: Enables the [`axum`] based service router. Enabled by default.\n//! - `codegen`: Enables all the required exports and optional dependencies required\n//!   for [`tonic-build`]. Enabled by default.\n//! - `tls-ring`: Enables the [`rustls`] based TLS options for the `transport` feature using\n//!   the [`ring`] libcrypto provider. Not enabled by default.\n//! - `tls-aws-lc`: Enables the [`rustls`] based TLS options for the `transport` feature using\n//!   the [`aws-lc-rs`] libcrypto provider. Not enabled by default.\n//! - `tls-native-roots`: Adds system trust roots to [`rustls`]-based gRPC clients using the\n//!   [`rustls-native-certs`] crate. Not enabled by default.\n//! - `tls-webpki-roots`: Add the standard trust roots from the [`webpki-roots`] crate to\n//!   `rustls`-based gRPC clients. Not enabled by default.\n//! - `tls-connect-info`: Adds additional implementations of [`Connected`]\n//!   on common TLS connectors. Not enabled by default, unless any of the other `tls-*`\n//!   features are enabled. This feature is useful for when trying to use a custom\n//!   TLS connector with `connect_with_connector` without enabling any `tls-*` features.\n//! - `gzip`: Enables compressing requests, responses, and streams. Depends on [`flate2`].\n//!   Not enabled by default.\n//! - `deflate`: Enables compressing requests, responses, and streams. Depends on [`flate2`].\n//!   Not enabled by default.\n//! - `zstd`: Enables compressing requests, responses, and streams. Depends on [`zstd`].\n//!   Not enabled by default.\n//!\n//! # Structure\n//!\n//! ## Generic implementation\n//!\n//! The main goal of [`tonic`] is to provide a generic gRPC implementation over HTTP/2\n//! framing. This means at the lowest level this library provides the ability to use\n//! a generic HTTP/2 implementation with different types of gRPC encodings formats. Generally,\n//! some form of codegen should be used instead of interacting directly with the items in\n//! [`client`] and [`server`].\n//!\n//! ## Transport\n//!\n//! The [`transport`] module contains a fully featured HTTP/2.0 [`Channel`] (gRPC terminology)\n//! and [`Server`]. These implementations are built on top of [`tokio`], [`hyper`] and [`tower`].\n//! It also provides many of the features that the core gRPC libraries provide such as load balancing,\n//! tls, timeouts, and many more. This implementation can also be used as a reference implementation\n//! to build even more feature rich clients and servers. This module also provides the ability to\n//! enable TLS using [`rustls`], via the `tls` feature flag.\n//!\n//! # Code generated client/server configuration\n//!\n//! ## Max Message Size\n//!\n//! Currently, both servers and clients can be configured to set the max message encoding and\n//! decoding size. This will ensure that an incoming gRPC message will not exhaust the systems\n//! memory. By default, the decoding message limit is `4MB` and the encoding limit is `usize::MAX`.\n//!\n//! [gRPC]: https://grpc.io\n//! [`tonic`]: https://github.com/hyperium/tonic\n//! [`tokio`]: https://docs.rs/tokio\n//! [`hyper`]: https://docs.rs/hyper\n//! [`tower`]: https://docs.rs/tower\n//! [`tonic-build`]: https://docs.rs/tonic-build\n//! [`ring`]: https://docs.rs/ring\n//! [`aws-lc-rs`]: https://docs.rs/aws-lc-rs\n//! [`tonic-examples`]: https://github.com/hyperium/tonic/tree/master/examples\n//! [`Codec`]: codec/trait.Codec.html\n//! [`Channel`]: transport/struct.Channel.html\n//! [`Server`]: transport/struct.Server.html\n//! [`Connected`]: transport/server/trait.Connected.html\n//! [`rustls`]: https://docs.rs/rustls\n//! [`client`]: client/index.html\n//! [`transport`]: transport/index.html\n//! [`rustls-native-certs`]: https://docs.rs/rustls-native-certs\n//! [`webpki-roots`]: https://docs.rs/webpki-roots\n//! [`flate2`]: https://docs.rs/flate2\n//! [`zstd`]: https://docs.rs/zstd\n\n#![recursion_limit = \"256\"]\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg\"\n)]\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\npub mod body;\npub mod client;\npub mod codec;\npub mod metadata;\npub mod server;\npub mod service;\n\n#[cfg(any(feature = \"server\", feature = \"channel\"))]\npub mod transport;\n\nmod extensions;\nmod macros;\nmod request;\nmod response;\nmod status;\nmod util;\n\n/// A re-export of [`async-trait`](https://docs.rs/async-trait) for use with codegen.\n#[cfg(feature = \"codegen\")]\npub use async_trait::async_trait;\n\n#[doc(inline)]\npub use codec::Streaming;\npub use extensions::GrpcMethod;\npub use http::Extensions;\npub use request::{IntoRequest, IntoStreamingRequest, Request};\npub use response::Response;\npub use status::{Code, ConnectError, Status, TimeoutExpired};\n\npub(crate) type BoxError = Box<dyn std::error::Error + Send + Sync>;\n\n#[doc(hidden)]\n#[cfg(feature = \"codegen\")]\npub mod codegen;\n\n/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).\n/// By default, the Err value is of type [`Status`] but this can be overridden if desired.\npub type Result<T, E = Status> = std::result::Result<T, E>;\n"
  },
  {
    "path": "tonic/src/macros.rs",
    "content": "/// Include generated proto server and client items.\n///\n/// You must specify the gRPC package name.\n///\n/// ```rust,ignore\n/// mod pb {\n///     tonic::include_proto!(\"helloworld\");\n/// }\n/// ```\n///\n/// # Note:\n/// **This only works if the tonic-build output directory has been unmodified**.\n/// The default output directory is set to the [`OUT_DIR`] environment variable.\n/// If the output directory has been modified, the following pattern may be used\n/// instead of this macro.\n///\n/// ```rust,ignore\n/// mod pb {\n///     include!(\"/relative/protobuf/directory/helloworld.rs\");\n/// }\n/// ```\n/// You can also use a custom environment variable using the following pattern.\n/// ```rust,ignore\n/// mod pb {\n///     include!(concat!(env!(\"PROTOBUFS\"), \"/helloworld.rs\"));\n/// }\n/// ```\n///\n/// [`OUT_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts\n#[macro_export]\nmacro_rules! include_proto {\n    ($package: tt) => {\n        include!(concat!(env!(\"OUT_DIR\"), concat!(\"/\", $package, \".rs\")));\n    };\n}\n\n/// Include an encoded `prost_types::FileDescriptorSet` as a `&'static [u8]`. The parameter must be\n/// the stem of the filename passed to `file_descriptor_set_path` for the `tonic-build::Builder`,\n/// excluding the `.bin` extension.\n///\n/// For example, a file descriptor set compiled like this in `build.rs`:\n///\n/// ```rust,ignore\n/// let descriptor_path = PathBuf::from(env::var(\"OUT_DIR\").unwrap()).join(\"my_descriptor.bin\")\n/// tonic_build::configure()\n///     .file_descriptor_set_path(&descriptor_path)\n///     .compile_protos(&[\"proto/reflection.proto\"], &[\"proto/\"])?;\n/// ```\n///\n/// Can be included like this:\n///\n/// ```rust,ignore\n/// mod pb {\n///     pub(crate) const FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!(\"my_descriptor\");\n/// }\n/// ```\n///\n/// # Note:\n/// **This only works if the tonic-build output directory has been unmodified**.\n/// The default output directory is set to the [`OUT_DIR`] environment variable.\n/// If the output directory has been modified, the following pattern may be used\n/// instead of this macro.\n///\n/// ```rust,ignore\n/// mod pb {\n///     pub(crate) const FILE_DESCRIPTOR_SET: &[u8] = include_bytes!(\"/relative/protobuf/directory/descriptor_name.bin\");\n/// }\n/// ```\n///\n/// [`OUT_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts\n#[macro_export]\nmacro_rules! include_file_descriptor_set {\n    ($package: tt) => {\n        include_bytes!(concat!(env!(\"OUT_DIR\"), concat!(\"/\", $package, \".bin\")))\n    };\n}\n"
  },
  {
    "path": "tonic/src/metadata/encoding.rs",
    "content": "use base64::Engine as _;\nuse bytes::Bytes;\nuse http::header::HeaderValue;\nuse std::error::Error;\nuse std::fmt;\nuse std::hash::Hash;\n\n/// A possible error when converting a `MetadataValue` from a string or byte\n/// slice.\n#[derive(Debug, Hash)]\npub struct InvalidMetadataValue {\n    _priv: (),\n}\n\nmod value_encoding {\n    use super::InvalidMetadataValueBytes;\n    use bytes::Bytes;\n    use http::header::HeaderValue;\n    use std::fmt;\n\n    pub trait Sealed {\n        #[doc(hidden)]\n        fn is_empty(value: &[u8]) -> bool;\n\n        #[doc(hidden)]\n        fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes>;\n\n        #[doc(hidden)]\n        fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes>;\n\n        #[doc(hidden)]\n        fn from_static(value: &'static str) -> HeaderValue;\n\n        #[doc(hidden)]\n        fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes>;\n\n        #[doc(hidden)]\n        fn equals(a: &HeaderValue, b: &[u8]) -> bool;\n\n        #[doc(hidden)]\n        fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool;\n\n        #[doc(hidden)]\n        fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result;\n    }\n}\n\npub trait ValueEncoding: Clone + Eq + PartialEq + Hash + self::value_encoding::Sealed {\n    /// Returns true if the provided key is valid for this ValueEncoding type.\n    /// For example, `Ascii::is_valid_key(\"a\") == true`,\n    /// `Ascii::is_valid_key(\"a-bin\") == false`.\n    fn is_valid_key(key: &str) -> bool;\n}\n\n/// gRPC metadata values can be either ASCII strings or binary. Note that only\n/// visible ASCII characters (32-127) are permitted.\n/// This type should never be instantiated -- in fact, it's impossible\n/// to, because there's no variants to instantiate. Instead, it's just used as\n/// a type parameter for [`MetadataKey`] and [`MetadataValue`].\n///\n/// [`MetadataKey`]: struct.MetadataKey.html\n/// [`MetadataValue`]: struct.MetadataValue.html\n#[derive(Clone, Debug, Eq, PartialEq, Hash)]\n#[non_exhaustive]\npub enum Ascii {}\n\n/// gRPC metadata values can be either ASCII strings or binary.\n/// This type should never be instantiated -- in fact, it's impossible\n/// to, because there's no variants to instantiate. Instead, it's just used as\n/// a type parameter for [`MetadataKey`] and [`MetadataValue`].\n///\n/// [`MetadataKey`]: struct.MetadataKey.html\n/// [`MetadataValue`]: struct.MetadataValue.html\n#[derive(Clone, Debug, Eq, PartialEq, Hash)]\n#[non_exhaustive]\npub enum Binary {}\n\n// ===== impl ValueEncoding =====\n\nimpl self::value_encoding::Sealed for Ascii {\n    fn is_empty(value: &[u8]) -> bool {\n        value.is_empty()\n    }\n\n    fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes> {\n        HeaderValue::from_bytes(value).map_err(|_| InvalidMetadataValueBytes::new())\n    }\n\n    fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes> {\n        HeaderValue::from_maybe_shared(value).map_err(|_| InvalidMetadataValueBytes::new())\n    }\n\n    fn from_static(value: &'static str) -> HeaderValue {\n        HeaderValue::from_static(value)\n    }\n\n    fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes> {\n        Ok(Bytes::copy_from_slice(value))\n    }\n\n    fn equals(a: &HeaderValue, b: &[u8]) -> bool {\n        a.as_bytes() == b\n    }\n\n    fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool {\n        a == b\n    }\n\n    fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(value, f)\n    }\n}\n\nimpl ValueEncoding for Ascii {\n    fn is_valid_key(key: &str) -> bool {\n        !Binary::is_valid_key(key)\n    }\n}\n\nimpl self::value_encoding::Sealed for Binary {\n    fn is_empty(value: &[u8]) -> bool {\n        for c in value {\n            if *c != b'=' {\n                return false;\n            }\n        }\n        true\n    }\n\n    fn from_bytes(value: &[u8]) -> Result<HeaderValue, InvalidMetadataValueBytes> {\n        let encoded_value: String = crate::util::base64::STANDARD_NO_PAD.encode(value);\n        HeaderValue::from_maybe_shared(Bytes::from(encoded_value))\n            .map_err(|_| InvalidMetadataValueBytes::new())\n    }\n\n    fn from_shared(value: Bytes) -> Result<HeaderValue, InvalidMetadataValueBytes> {\n        Self::from_bytes(value.as_ref())\n    }\n\n    fn from_static(value: &'static str) -> HeaderValue {\n        if crate::util::base64::STANDARD.decode(value).is_err() {\n            panic!(\"Invalid base64 passed to from_static: {value}\");\n        }\n        unsafe {\n            // Because this is valid base64 this must be a valid HTTP header value,\n            // no need to check again by calling from_shared.\n            HeaderValue::from_maybe_shared_unchecked(Bytes::from_static(value.as_ref()))\n        }\n    }\n\n    fn decode(value: &[u8]) -> Result<Bytes, InvalidMetadataValueBytes> {\n        crate::util::base64::STANDARD\n            .decode(value)\n            .map(|bytes_vec| bytes_vec.into())\n            .map_err(|_| InvalidMetadataValueBytes::new())\n    }\n\n    fn equals(a: &HeaderValue, b: &[u8]) -> bool {\n        if let Ok(decoded) = crate::util::base64::STANDARD.decode(a.as_bytes()) {\n            decoded == b\n        } else {\n            a.as_bytes() == b\n        }\n    }\n\n    fn values_equal(a: &HeaderValue, b: &HeaderValue) -> bool {\n        match (Self::decode(a.as_bytes()), Self::decode(b.as_bytes())) {\n            (Ok(a), Ok(b)) => a == b,\n            (Err(_), Err(_)) => true,\n            _ => false,\n        }\n    }\n\n    fn fmt(value: &HeaderValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        if let Ok(decoded) = Self::decode(value.as_bytes()) {\n            write!(f, \"{decoded:?}\")\n        } else {\n            write!(f, \"b[invalid]{value:?}\")\n        }\n    }\n}\n\nimpl ValueEncoding for Binary {\n    fn is_valid_key(key: &str) -> bool {\n        key.ends_with(\"-bin\")\n    }\n}\n\n// ===== impl InvalidMetadataValue =====\n\nimpl InvalidMetadataValue {\n    pub(crate) fn new() -> Self {\n        InvalidMetadataValue { _priv: () }\n    }\n}\n\nimpl fmt::Display for InvalidMetadataValue {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"failed to parse metadata value\")\n    }\n}\n\nimpl Error for InvalidMetadataValue {}\n\n/// A possible error when converting a `MetadataValue` from a string or byte\n/// slice.\n#[derive(Debug, Hash)]\npub struct InvalidMetadataValueBytes(InvalidMetadataValue);\n\n// ===== impl InvalidMetadataValueBytes =====\n\nimpl InvalidMetadataValueBytes {\n    pub(crate) fn new() -> Self {\n        InvalidMetadataValueBytes(InvalidMetadataValue::new())\n    }\n}\n\nimpl fmt::Display for InvalidMetadataValueBytes {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.0.fmt(f)\n    }\n}\n\nimpl Error for InvalidMetadataValueBytes {}\n"
  },
  {
    "path": "tonic/src/metadata/key.rs",
    "content": "use bytes::Bytes;\nuse http::header::HeaderName;\nuse std::borrow::Borrow;\nuse std::error::Error;\nuse std::fmt;\nuse std::marker::PhantomData;\nuse std::str::FromStr;\n\nuse super::encoding::{Ascii, Binary, ValueEncoding};\n\n/// Represents a custom metadata field name.\n///\n/// `MetadataKey` is used as the [`MetadataMap`] key.\n///\n/// [`HeaderMap`]: struct.HeaderMap.html\n/// [`MetadataMap`]: struct.MetadataMap.html\n#[derive(Clone, Eq, PartialEq, Hash)]\n#[repr(transparent)]\npub struct MetadataKey<VE: ValueEncoding> {\n    // Note: There are unsafe transmutes that assume that the memory layout\n    // of MetadataValue is identical to HeaderName\n    pub(crate) inner: http::header::HeaderName,\n    phantom: PhantomData<VE>,\n}\n\n/// A possible error when converting a `MetadataKey` from another type.\n#[derive(Debug, Default)]\npub struct InvalidMetadataKey {\n    _priv: (),\n}\n\n/// An ascii metadata key.\npub type AsciiMetadataKey = MetadataKey<Ascii>;\n/// A binary metadata key.\npub type BinaryMetadataKey = MetadataKey<Binary>;\n\nimpl<VE: ValueEncoding> MetadataKey<VE> {\n    /// Converts a slice of bytes to a `MetadataKey`.\n    ///\n    /// This function normalizes the input.\n    pub fn from_bytes(src: &[u8]) -> Result<Self, InvalidMetadataKey> {\n        match HeaderName::from_bytes(src) {\n            Ok(name) => {\n                if !VE::is_valid_key(name.as_str()) {\n                    return Err(InvalidMetadataKey::new());\n                }\n\n                Ok(MetadataKey {\n                    inner: name,\n                    phantom: PhantomData,\n                })\n            }\n            Err(_) => Err(InvalidMetadataKey::new()),\n        }\n    }\n\n    /// Converts a static string to a `MetadataKey`.\n    ///\n    /// This function panics when the static string is a invalid metadata key.\n    ///\n    /// This function requires the static string to only contain lowercase\n    /// characters, numerals and symbols, as per the HTTP/2.0 specification\n    /// and header names internal representation within this library.\n    ///\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// // Parsing a metadata key\n    /// let CUSTOM_KEY: &'static str = \"custom-key\";\n    ///\n    /// let a = AsciiMetadataKey::from_bytes(b\"custom-key\").unwrap();\n    /// let b = AsciiMetadataKey::from_static(CUSTOM_KEY);\n    /// assert_eq!(a, b);\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// // Parsing a metadata key that contains invalid symbols(s):\n    /// AsciiMetadataKey::from_static(\"content{}{}length\"); // This line panics!\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// // Parsing a metadata key that contains invalid uppercase characters.\n    /// let a = AsciiMetadataKey::from_static(\"foobar\");\n    /// let b = AsciiMetadataKey::from_static(\"FOOBAR\"); // This line panics!\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// // Parsing a -bin metadata key as an Ascii key.\n    /// let b = AsciiMetadataKey::from_static(\"hello-bin\"); // This line panics!\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// // Parsing a non-bin metadata key as an Binary key.\n    /// let b = BinaryMetadataKey::from_static(\"hello\"); // This line panics!\n    /// ```\n    pub fn from_static(src: &'static str) -> Self {\n        let name = HeaderName::from_static(src);\n        if !VE::is_valid_key(name.as_str()) {\n            panic!(\"invalid metadata key\")\n        }\n\n        MetadataKey {\n            inner: name,\n            phantom: PhantomData,\n        }\n    }\n\n    /// Returns a `str` representation of the metadata key.\n    ///\n    /// The returned string will always be lower case.\n    #[inline]\n    pub fn as_str(&self) -> &str {\n        self.inner.as_str()\n    }\n\n    /// Converts a HeaderName reference to a MetadataKey. This method assumes\n    /// that the caller has made sure that the header name has the correct\n    /// \"-bin\" or non-\"-bin\" suffix, it does not validate its input.\n    #[inline]\n    pub(crate) fn unchecked_from_header_name_ref(header_name: &HeaderName) -> &Self {\n        unsafe { &*(header_name as *const HeaderName as *const Self) }\n    }\n\n    /// Converts a HeaderName reference to a MetadataKey. This method assumes\n    /// that the caller has made sure that the header name has the correct\n    /// \"-bin\" or non-\"-bin\" suffix, it does not validate its input.\n    #[inline]\n    pub(crate) fn unchecked_from_header_name(name: HeaderName) -> Self {\n        MetadataKey {\n            inner: name,\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<VE: ValueEncoding> FromStr for MetadataKey<VE> {\n    type Err = InvalidMetadataKey;\n\n    fn from_str(s: &str) -> Result<Self, InvalidMetadataKey> {\n        MetadataKey::from_bytes(s.as_bytes()).map_err(|_| InvalidMetadataKey::new())\n    }\n}\n\nimpl<VE: ValueEncoding> AsRef<str> for MetadataKey<VE> {\n    fn as_ref(&self) -> &str {\n        self.as_str()\n    }\n}\n\nimpl<VE: ValueEncoding> AsRef<[u8]> for MetadataKey<VE> {\n    fn as_ref(&self) -> &[u8] {\n        self.as_str().as_bytes()\n    }\n}\n\nimpl<VE: ValueEncoding> Borrow<str> for MetadataKey<VE> {\n    fn borrow(&self) -> &str {\n        self.as_str()\n    }\n}\n\nimpl<VE: ValueEncoding> fmt::Debug for MetadataKey<VE> {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(self.as_str(), fmt)\n    }\n}\n\nimpl<VE: ValueEncoding> fmt::Display for MetadataKey<VE> {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Display::fmt(self.as_str(), fmt)\n    }\n}\n\nimpl InvalidMetadataKey {\n    #[doc(hidden)]\n    pub fn new() -> InvalidMetadataKey {\n        Self::default()\n    }\n}\n\nimpl<'a, VE: ValueEncoding> From<&'a MetadataKey<VE>> for MetadataKey<VE> {\n    fn from(src: &'a MetadataKey<VE>) -> MetadataKey<VE> {\n        src.clone()\n    }\n}\n\nimpl<VE: ValueEncoding> From<MetadataKey<VE>> for Bytes {\n    #[inline]\n    fn from(name: MetadataKey<VE>) -> Bytes {\n        Bytes::copy_from_slice(name.inner.as_ref())\n    }\n}\n\nimpl<'a, VE: ValueEncoding> PartialEq<&'a MetadataKey<VE>> for MetadataKey<VE> {\n    #[inline]\n    fn eq(&self, other: &&'a MetadataKey<VE>) -> bool {\n        *self == **other\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataKey<VE>> for &MetadataKey<VE> {\n    #[inline]\n    fn eq(&self, other: &MetadataKey<VE>) -> bool {\n        *other == *self\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<str> for MetadataKey<VE> {\n    /// Performs a case-insensitive comparison of the string against the header\n    /// name\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let content_length = AsciiMetadataKey::from_static(\"content-length\");\n    ///\n    /// assert_eq!(content_length, \"content-length\");\n    /// assert_eq!(content_length, \"Content-Length\");\n    /// assert_ne!(content_length, \"content length\");\n    /// ```\n    #[inline]\n    fn eq(&self, other: &str) -> bool {\n        self.inner.eq(other)\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataKey<VE>> for str {\n    /// Performs a case-insensitive comparison of the string against the header\n    /// name\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let content_length = AsciiMetadataKey::from_static(\"content-length\");\n    ///\n    /// assert_eq!(content_length, \"content-length\");\n    /// assert_eq!(content_length, \"Content-Length\");\n    /// assert_ne!(content_length, \"content length\");\n    /// ```\n    #[inline]\n    fn eq(&self, other: &MetadataKey<VE>) -> bool {\n        other.inner == *self\n    }\n}\n\nimpl<'a, VE: ValueEncoding> PartialEq<&'a str> for MetadataKey<VE> {\n    /// Performs a case-insensitive comparison of the string against the header\n    /// name\n    #[inline]\n    fn eq(&self, other: &&'a str) -> bool {\n        *self == **other\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataKey<VE>> for &str {\n    /// Performs a case-insensitive comparison of the string against the header\n    /// name\n    #[inline]\n    fn eq(&self, other: &MetadataKey<VE>) -> bool {\n        *other == *self\n    }\n}\n\nimpl fmt::Display for InvalidMetadataKey {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"invalid gRPC metadata key name\")\n    }\n}\n\nimpl Error for InvalidMetadataKey {}\n\n#[cfg(test)]\nmod tests {\n    use super::{AsciiMetadataKey, BinaryMetadataKey};\n\n    #[test]\n    fn test_from_bytes_binary() {\n        assert!(BinaryMetadataKey::from_bytes(b\"\").is_err());\n        assert!(BinaryMetadataKey::from_bytes(b\"\\xFF\").is_err());\n        assert!(BinaryMetadataKey::from_bytes(b\"abc\").is_err());\n        assert_eq!(\n            BinaryMetadataKey::from_bytes(b\"abc-bin\").unwrap().as_str(),\n            \"abc-bin\"\n        );\n    }\n\n    #[test]\n    fn test_from_bytes_ascii() {\n        assert!(AsciiMetadataKey::from_bytes(b\"\").is_err());\n        assert!(AsciiMetadataKey::from_bytes(b\"\\xFF\").is_err());\n        assert_eq!(\n            AsciiMetadataKey::from_bytes(b\"abc\").unwrap().as_str(),\n            \"abc\"\n        );\n        assert!(AsciiMetadataKey::from_bytes(b\"abc-bin\").is_err());\n    }\n}\n"
  },
  {
    "path": "tonic/src/metadata/map.rs",
    "content": "use http::HeaderName;\n\npub(crate) use self::as_encoding_agnostic_metadata_key::AsEncodingAgnosticMetadataKey;\npub(crate) use self::as_metadata_key::AsMetadataKey;\npub(crate) use self::into_metadata_key::IntoMetadataKey;\n\nuse super::encoding::{Ascii, Binary, ValueEncoding};\nuse super::key::{InvalidMetadataKey, MetadataKey};\nuse super::value::MetadataValue;\n\nuse std::marker::PhantomData;\n\n/// A set of gRPC custom metadata entries.\n///\n/// # Examples\n///\n/// Basic usage\n///\n/// ```\n/// # use tonic::metadata::*;\n/// let mut map = MetadataMap::new();\n///\n/// map.insert(\"x-host\", \"example.com\".parse().unwrap());\n/// map.insert(\"x-number\", \"123\".parse().unwrap());\n/// map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"[binary data]\"));\n///\n/// assert!(map.contains_key(\"x-host\"));\n/// assert!(!map.contains_key(\"x-location\"));\n///\n/// assert_eq!(map.get(\"x-host\").unwrap(), \"example.com\");\n///\n/// map.remove(\"x-host\");\n///\n/// assert!(!map.contains_key(\"x-host\"));\n/// ```\n#[derive(Clone, Debug, Default)]\npub struct MetadataMap {\n    headers: http::HeaderMap,\n}\n\nimpl AsRef<http::HeaderMap> for MetadataMap {\n    fn as_ref(&self) -> &http::HeaderMap {\n        &self.headers\n    }\n}\n\nimpl AsMut<http::HeaderMap> for MetadataMap {\n    fn as_mut(&mut self) -> &mut http::HeaderMap {\n        &mut self.headers\n    }\n}\n\n/// `MetadataMap` entry iterator.\n///\n/// Yields `KeyAndValueRef` values. The same header name may be yielded\n/// more than once if it has more than one associated value.\n#[derive(Debug)]\npub struct Iter<'a> {\n    inner: http::header::Iter<'a, http::header::HeaderValue>,\n}\n\n/// Reference to a key and an associated value in a `MetadataMap`. It can point\n/// to either an ascii or a binary (\"*-bin\") key.\n#[derive(Debug)]\npub enum KeyAndValueRef<'a> {\n    /// An ascii metadata key and value.\n    Ascii(&'a MetadataKey<Ascii>, &'a MetadataValue<Ascii>),\n    /// A binary metadata key and value.\n    Binary(&'a MetadataKey<Binary>, &'a MetadataValue<Binary>),\n}\n\n/// Reference to a key and an associated value in a `MetadataMap`. It can point\n/// to either an ascii or a binary (\"*-bin\") key.\n#[derive(Debug)]\npub enum KeyAndMutValueRef<'a> {\n    /// An ascii metadata key and value.\n    Ascii(&'a MetadataKey<Ascii>, &'a mut MetadataValue<Ascii>),\n    /// A binary metadata key and value.\n    Binary(&'a MetadataKey<Binary>, &'a mut MetadataValue<Binary>),\n}\n\n/// `MetadataMap` entry iterator.\n///\n/// Yields `(&MetadataKey, &mut value)` tuples. The same header name may be yielded\n/// more than once if it has more than one associated value.\n#[derive(Debug)]\npub struct IterMut<'a> {\n    inner: http::header::IterMut<'a, http::header::HeaderValue>,\n}\n\n/// A drain iterator of all values associated with a single metadata key.\n#[derive(Debug)]\npub struct ValueDrain<'a, VE: ValueEncoding> {\n    inner: http::header::ValueDrain<'a, http::header::HeaderValue>,\n    phantom: PhantomData<VE>,\n}\n\n/// An iterator over `MetadataMap` keys.\n///\n/// Yields `KeyRef` values. Each header name is yielded only once, even if it\n/// has more than one associated value.\n#[derive(Debug)]\npub struct Keys<'a> {\n    inner: http::header::Keys<'a, http::header::HeaderValue>,\n}\n\n/// Reference to a key in a `MetadataMap`. It can point\n/// to either an ascii or a binary (\"*-bin\") key.\n#[derive(Debug)]\npub enum KeyRef<'a> {\n    /// An ascii metadata key and value.\n    Ascii(&'a MetadataKey<Ascii>),\n    /// A binary metadata key and value.\n    Binary(&'a MetadataKey<Binary>),\n}\n\n/// `MetadataMap` value iterator.\n///\n/// Yields `ValueRef` values. Each value contained in the `MetadataMap` will be\n/// yielded.\n#[derive(Debug)]\npub struct Values<'a> {\n    // Need to use http::header::Iter and not http::header::Values to be able\n    // to know if a value is binary or not.\n    inner: http::header::Iter<'a, http::header::HeaderValue>,\n}\n\n/// Reference to a value in a `MetadataMap`. It can point\n/// to either an ascii or a binary (\"*-bin\" key) value.\n#[derive(Debug)]\npub enum ValueRef<'a> {\n    /// An ascii metadata key and value.\n    Ascii(&'a MetadataValue<Ascii>),\n    /// A binary metadata key and value.\n    Binary(&'a MetadataValue<Binary>),\n}\n\n/// `MetadataMap` value iterator.\n///\n/// Each value contained in the `MetadataMap` will be yielded.\n#[derive(Debug)]\npub struct ValuesMut<'a> {\n    // Need to use http::header::IterMut and not http::header::ValuesMut to be\n    // able to know if a value is binary or not.\n    inner: http::header::IterMut<'a, http::header::HeaderValue>,\n}\n\n/// Reference to a value in a `MetadataMap`. It can point\n/// to either an ascii or a binary (\"*-bin\" key) value.\n#[derive(Debug)]\npub enum ValueRefMut<'a> {\n    /// An ascii metadata key and value.\n    Ascii(&'a mut MetadataValue<Ascii>),\n    /// A binary metadata key and value.\n    Binary(&'a mut MetadataValue<Binary>),\n}\n\n/// An iterator of all values associated with a single metadata key.\n#[derive(Debug)]\npub struct ValueIter<'a, VE: ValueEncoding> {\n    inner: Option<http::header::ValueIter<'a, http::header::HeaderValue>>,\n    phantom: PhantomData<VE>,\n}\n\n/// An iterator of all values associated with a single metadata key.\n#[derive(Debug)]\npub struct ValueIterMut<'a, VE: ValueEncoding> {\n    inner: http::header::ValueIterMut<'a, http::header::HeaderValue>,\n    phantom: PhantomData<VE>,\n}\n\n/// A view to all values stored in a single entry.\n///\n/// This struct is returned by `MetadataMap::get_all` and\n/// `MetadataMap::get_all_bin`.\n#[derive(Debug)]\npub struct GetAll<'a, VE: ValueEncoding> {\n    inner: Option<http::header::GetAll<'a, http::header::HeaderValue>>,\n    phantom: PhantomData<VE>,\n}\n\n/// A view into a single location in a `MetadataMap`, which may be vacant or\n/// occupied.\n#[derive(Debug)]\npub enum Entry<'a, VE: ValueEncoding> {\n    /// An occupied entry\n    Occupied(OccupiedEntry<'a, VE>),\n\n    /// A vacant entry\n    Vacant(VacantEntry<'a, VE>),\n}\n\n/// A view into a single empty location in a `MetadataMap`.\n///\n/// This struct is returned as part of the `Entry` enum.\n#[derive(Debug)]\npub struct VacantEntry<'a, VE: ValueEncoding> {\n    inner: http::header::VacantEntry<'a, http::header::HeaderValue>,\n    phantom: PhantomData<VE>,\n}\n\n/// A view into a single occupied location in a `MetadataMap`.\n///\n/// This struct is returned as part of the `Entry` enum.\n#[derive(Debug)]\npub struct OccupiedEntry<'a, VE: ValueEncoding> {\n    inner: http::header::OccupiedEntry<'a, http::header::HeaderValue>,\n    phantom: PhantomData<VE>,\n}\n\npub(crate) const GRPC_TIMEOUT_HEADER: &str = \"grpc-timeout\";\n\n// ===== impl MetadataMap =====\n\nimpl MetadataMap {\n    // Headers reserved by the gRPC protocol.\n    pub(crate) const GRPC_RESERVED_HEADERS: [HeaderName; 5] = [\n        HeaderName::from_static(\"te\"),\n        HeaderName::from_static(\"content-type\"),\n        HeaderName::from_static(\"grpc-message\"),\n        HeaderName::from_static(\"grpc-message-type\"),\n        HeaderName::from_static(\"grpc-status\"),\n    ];\n\n    /// Create an empty `MetadataMap`.\n    ///\n    /// The map will be created without any capacity. This function will not\n    /// allocate.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let map = MetadataMap::new();\n    ///\n    /// assert!(map.is_empty());\n    /// assert_eq!(0, map.capacity());\n    /// ```\n    pub fn new() -> Self {\n        MetadataMap::with_capacity(0)\n    }\n\n    /// Convert an HTTP HeaderMap to a MetadataMap\n    pub fn from_headers(headers: http::HeaderMap) -> Self {\n        MetadataMap { headers }\n    }\n\n    /// Convert a MetadataMap into a HTTP HeaderMap\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"x-host\", \"example.com\".parse().unwrap());\n    ///\n    /// let http_map = map.into_headers();\n    ///\n    /// assert_eq!(http_map.get(\"x-host\").unwrap(), \"example.com\");\n    /// ```\n    pub fn into_headers(self) -> http::HeaderMap {\n        self.headers\n    }\n\n    pub(crate) fn into_sanitized_headers(mut self) -> http::HeaderMap {\n        for r in &Self::GRPC_RESERVED_HEADERS {\n            self.headers.remove(r);\n        }\n        self.headers\n    }\n\n    /// Create an empty `MetadataMap` with the specified capacity.\n    ///\n    /// The returned map will allocate internal storage in order to hold about\n    /// `capacity` elements without reallocating. However, this is a \"best\n    /// effort\" as there are usage patterns that could cause additional\n    /// allocations before `capacity` metadata entries are stored in the map.\n    ///\n    /// More capacity than requested may be allocated.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let map: MetadataMap = MetadataMap::with_capacity(10);\n    ///\n    /// assert!(map.is_empty());\n    /// assert!(map.capacity() >= 10);\n    /// ```\n    pub fn with_capacity(capacity: usize) -> MetadataMap {\n        MetadataMap {\n            headers: http::HeaderMap::with_capacity(capacity),\n        }\n    }\n\n    /// Returns the number of metadata entries (ascii and binary) stored in the\n    /// map.\n    ///\n    /// This number represents the total number of **values** stored in the map.\n    /// This number can be greater than or equal to the number of **keys**\n    /// stored given that a single key may have more than one associated value.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// assert_eq!(0, map.len());\n    ///\n    /// map.insert(\"x-host-ip\", \"127.0.0.1\".parse().unwrap());\n    /// map.insert_bin(\"x-host-name-bin\", MetadataValue::from_bytes(b\"localhost\"));\n    ///\n    /// assert_eq!(2, map.len());\n    ///\n    /// map.append(\"x-host-ip\", \"text/html\".parse().unwrap());\n    ///\n    /// assert_eq!(3, map.len());\n    /// ```\n    pub fn len(&self) -> usize {\n        self.headers.len()\n    }\n\n    /// Returns the number of keys (ascii and binary) stored in the map.\n    ///\n    /// This number will be less than or equal to `len()` as each key may have\n    /// more than one associated value.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// assert_eq!(0, map.keys_len());\n    ///\n    /// map.insert(\"x-host-ip\", \"127.0.0.1\".parse().unwrap());\n    /// map.insert_bin(\"x-host-name-bin\", MetadataValue::from_bytes(b\"localhost\"));\n    ///\n    /// assert_eq!(2, map.keys_len());\n    ///\n    /// map.append(\"x-host-ip\", \"text/html\".parse().unwrap());\n    ///\n    /// assert_eq!(2, map.keys_len());\n    /// ```\n    pub fn keys_len(&self) -> usize {\n        self.headers.keys_len()\n    }\n\n    /// Returns true if the map contains no elements.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// assert!(map.is_empty());\n    ///\n    /// map.insert(\"x-host\", \"hello.world\".parse().unwrap());\n    ///\n    /// assert!(!map.is_empty());\n    /// ```\n    pub fn is_empty(&self) -> bool {\n        self.headers.is_empty()\n    }\n\n    /// Clears the map, removing all key-value pairs. Keeps the allocated memory\n    /// for reuse.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"x-host\", \"hello.world\".parse().unwrap());\n    ///\n    /// map.clear();\n    /// assert!(map.is_empty());\n    /// assert!(map.capacity() > 0);\n    /// ```\n    pub fn clear(&mut self) {\n        self.headers.clear();\n    }\n\n    /// Returns the number of custom metadata entries the map can hold without\n    /// reallocating.\n    ///\n    /// This number is an approximation as certain usage patterns could cause\n    /// additional allocations before the returned capacity is filled.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// assert_eq!(0, map.capacity());\n    ///\n    /// map.insert(\"x-host\", \"hello.world\".parse().unwrap());\n    /// assert_eq!(6, map.capacity());\n    /// ```\n    pub fn capacity(&self) -> usize {\n        self.headers.capacity()\n    }\n\n    /// Reserves capacity for at least `additional` more custom metadata to be\n    /// inserted into the `MetadataMap`.\n    ///\n    /// The metadata map may reserve more space to avoid frequent reallocations.\n    /// Like with `with_capacity`, this will be a \"best effort\" to avoid\n    /// allocations until `additional` more custom metadata is inserted. Certain\n    /// usage patterns could cause additional allocations before the number is\n    /// reached.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the new allocation size overflows `usize`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.reserve(10);\n    /// # map.insert(\"x-host\", \"bar\".parse().unwrap());\n    /// ```\n    pub fn reserve(&mut self, additional: usize) {\n        self.headers.reserve(additional);\n    }\n\n    /// Returns a reference to the value associated with the key. This method\n    /// is for ascii metadata entries (those whose names don't end with\n    /// \"-bin\"). For binary entries, use get_bin.\n    ///\n    /// If there are multiple values associated with the key, then the first one\n    /// is returned. Use `get_all` to get all values associated with a given\n    /// key. Returns `None` if there are no values associated with the key.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// assert!(map.get(\"x-host\").is_none());\n    ///\n    /// map.insert(\"x-host\", \"hello\".parse().unwrap());\n    /// assert_eq!(map.get(\"x-host\").unwrap(), &\"hello\");\n    /// assert_eq!(map.get(\"x-host\").unwrap(), &\"hello\");\n    ///\n    /// map.append(\"x-host\", \"world\".parse().unwrap());\n    /// assert_eq!(map.get(\"x-host\").unwrap(), &\"hello\");\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append_bin(\"host-bin\", MetadataValue::from_bytes(b\"world\"));\n    /// assert!(map.get(\"host-bin\").is_none());\n    /// assert!(map.get(\"host-bin\".to_string()).is_none());\n    /// assert!(map.get(&(\"host-bin\".to_string())).is_none());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.get(\"host{}bin\").is_none());\n    /// assert!(map.get(\"host{}bin\".to_string()).is_none());\n    /// assert!(map.get(&(\"host{}bin\".to_string())).is_none());\n    /// ```\n    pub fn get<K>(&self, key: K) -> Option<&MetadataValue<Ascii>>\n    where\n        K: AsMetadataKey<Ascii>,\n    {\n        key.get(self)\n    }\n\n    /// Like get, but for Binary keys (for example \"trace-proto-bin\").\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// assert!(map.get_bin(\"trace-proto-bin\").is_none());\n    ///\n    /// map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"hello\"));\n    /// assert_eq!(map.get_bin(\"trace-proto-bin\").unwrap(), &\"hello\");\n    /// assert_eq!(map.get_bin(\"trace-proto-bin\").unwrap(), &\"hello\");\n    ///\n    /// map.append_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"world\"));\n    /// assert_eq!(map.get_bin(\"trace-proto-bin\").unwrap(), &\"hello\");\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append(\"host\", \"world\".parse().unwrap());\n    /// assert!(map.get_bin(\"host\").is_none());\n    /// assert!(map.get_bin(\"host\".to_string()).is_none());\n    /// assert!(map.get_bin(&(\"host\".to_string())).is_none());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.get_bin(\"host{}-bin\").is_none());\n    /// assert!(map.get_bin(\"host{}-bin\".to_string()).is_none());\n    /// assert!(map.get_bin(&(\"host{}-bin\".to_string())).is_none());\n    /// ```\n    pub fn get_bin<K>(&self, key: K) -> Option<&MetadataValue<Binary>>\n    where\n        K: AsMetadataKey<Binary>,\n    {\n        key.get(self)\n    }\n\n    /// Returns a mutable reference to the value associated with the key. This\n    /// method is for ascii metadata entries (those whose names don't end with\n    /// \"-bin\"). For binary entries, use get_mut_bin.\n    ///\n    /// If there are multiple values associated with the key, then the first one\n    /// is returned. Use `entry` to get all values associated with a given\n    /// key. Returns `None` if there are no values associated with the key.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    /// map.insert(\"x-host\", \"hello\".parse().unwrap());\n    /// map.get_mut(\"x-host\").unwrap().set_sensitive(true);\n    ///\n    /// assert!(map.get(\"x-host\").unwrap().is_sensitive());\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append_bin(\"host-bin\", MetadataValue::from_bytes(b\"world\"));\n    /// assert!(map.get_mut(\"host-bin\").is_none());\n    /// assert!(map.get_mut(\"host-bin\".to_string()).is_none());\n    /// assert!(map.get_mut(&(\"host-bin\".to_string())).is_none());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.get_mut(\"host{}\").is_none());\n    /// assert!(map.get_mut(\"host{}\".to_string()).is_none());\n    /// assert!(map.get_mut(&(\"host{}\".to_string())).is_none());\n    /// ```\n    pub fn get_mut<K>(&mut self, key: K) -> Option<&mut MetadataValue<Ascii>>\n    where\n        K: AsMetadataKey<Ascii>,\n    {\n        key.get_mut(self)\n    }\n\n    /// Like get_mut, but for Binary keys (for example \"trace-proto-bin\").\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    /// map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"hello\"));\n    /// map.get_bin_mut(\"trace-proto-bin\").unwrap().set_sensitive(true);\n    ///\n    /// assert!(map.get_bin(\"trace-proto-bin\").unwrap().is_sensitive());\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append(\"host\", \"world\".parse().unwrap());\n    /// assert!(map.get_bin_mut(\"host\").is_none());\n    /// assert!(map.get_bin_mut(\"host\".to_string()).is_none());\n    /// assert!(map.get_bin_mut(&(\"host\".to_string())).is_none());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.get_bin_mut(\"host{}-bin\").is_none());\n    /// assert!(map.get_bin_mut(\"host{}-bin\".to_string()).is_none());\n    /// assert!(map.get_bin_mut(&(\"host{}-bin\".to_string())).is_none());\n    /// ```\n    pub fn get_bin_mut<K>(&mut self, key: K) -> Option<&mut MetadataValue<Binary>>\n    where\n        K: AsMetadataKey<Binary>,\n    {\n        key.get_mut(self)\n    }\n\n    /// Returns a view of all values associated with a key. This method is for\n    /// ascii metadata entries (those whose names don't end with \"-bin\"). For\n    /// binary entries, use get_all_bin.\n    ///\n    /// The returned view does not incur any allocations and allows iterating\n    /// the values associated with the key.  See [`GetAll`] for more details.\n    /// Returns `None` if there are no values associated with the key.\n    ///\n    /// [`GetAll`]: struct.GetAll.html\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// map.insert(\"x-host\", \"hello\".parse().unwrap());\n    /// map.append(\"x-host\", \"goodbye\".parse().unwrap());\n    ///\n    /// {\n    ///     let view = map.get_all(\"x-host\");\n    ///\n    ///     let mut iter = view.iter();\n    ///     assert_eq!(&\"hello\", iter.next().unwrap());\n    ///     assert_eq!(&\"goodbye\", iter.next().unwrap());\n    ///     assert!(iter.next().is_none());\n    /// }\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append_bin(\"host-bin\", MetadataValue::from_bytes(b\"world\"));\n    /// assert!(map.get_all(\"host-bin\").iter().next().is_none());\n    /// assert!(map.get_all(\"host-bin\".to_string()).iter().next().is_none());\n    /// assert!(map.get_all(&(\"host-bin\".to_string())).iter().next().is_none());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.get_all(\"host{}\").iter().next().is_none());\n    /// assert!(map.get_all(\"host{}\".to_string()).iter().next().is_none());\n    /// assert!(map.get_all(&(\"host{}\".to_string())).iter().next().is_none());\n    /// ```\n    pub fn get_all<K>(&self, key: K) -> GetAll<'_, Ascii>\n    where\n        K: AsMetadataKey<Ascii>,\n    {\n        GetAll {\n            inner: key.get_all(self),\n            phantom: PhantomData,\n        }\n    }\n\n    /// Like get_all, but for Binary keys (for example \"trace-proto-bin\").\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"hello\"));\n    /// map.append_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n    ///\n    /// {\n    ///     let view = map.get_all_bin(\"trace-proto-bin\");\n    ///\n    ///     let mut iter = view.iter();\n    ///     assert_eq!(&\"hello\", iter.next().unwrap());\n    ///     assert_eq!(&\"goodbye\", iter.next().unwrap());\n    ///     assert!(iter.next().is_none());\n    /// }\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append(\"host\", \"world\".parse().unwrap());\n    /// assert!(map.get_all_bin(\"host\").iter().next().is_none());\n    /// assert!(map.get_all_bin(\"host\".to_string()).iter().next().is_none());\n    /// assert!(map.get_all_bin(&(\"host\".to_string())).iter().next().is_none());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.get_all_bin(\"host{}-bin\").iter().next().is_none());\n    /// assert!(map.get_all_bin(\"host{}-bin\".to_string()).iter().next().is_none());\n    /// assert!(map.get_all_bin(&(\"host{}-bin\".to_string())).iter().next().is_none());\n    /// ```\n    pub fn get_all_bin<K>(&self, key: K) -> GetAll<'_, Binary>\n    where\n        K: AsMetadataKey<Binary>,\n    {\n        GetAll {\n            inner: key.get_all(self),\n            phantom: PhantomData,\n        }\n    }\n\n    /// Returns true if the map contains a value for the specified key. This\n    /// method works for both ascii and binary entries.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// assert!(!map.contains_key(\"x-host\"));\n    ///\n    /// map.append_bin(\"host-bin\", MetadataValue::from_bytes(b\"world\"));\n    /// map.insert(\"x-host\", \"world\".parse().unwrap());\n    ///\n    /// // contains_key works for both Binary and Ascii keys:\n    /// assert!(map.contains_key(\"x-host\"));\n    /// assert!(map.contains_key(\"host-bin\"));\n    ///\n    /// // contains_key returns false for invalid keys:\n    /// assert!(!map.contains_key(\"x{}host\"));\n    /// ```\n    pub fn contains_key<K>(&self, key: K) -> bool\n    where\n        K: AsEncodingAgnosticMetadataKey,\n    {\n        key.contains_key(self)\n    }\n\n    /// An iterator visiting all key-value pairs (both ascii and binary).\n    ///\n    /// The iteration order is arbitrary, but consistent across platforms for\n    /// the same crate version. Each key will be yielded once per associated\n    /// value. So, if a key has 3 associated values, it will be yielded 3 times.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// map.insert(\"x-word\", \"hello\".parse().unwrap());\n    /// map.append(\"x-word\", \"goodbye\".parse().unwrap());\n    /// map.insert(\"x-number\", \"123\".parse().unwrap());\n    ///\n    /// for key_and_value in map.iter() {\n    ///     match key_and_value {\n    ///         KeyAndValueRef::Ascii(ref key, ref value) =>\n    ///             println!(\"Ascii: {:?}: {:?}\", key, value),\n    ///         KeyAndValueRef::Binary(ref key, ref value) =>\n    ///             println!(\"Binary: {:?}: {:?}\", key, value),\n    ///     }\n    /// }\n    /// ```\n    pub fn iter(&self) -> Iter<'_> {\n        Iter {\n            inner: self.headers.iter(),\n        }\n    }\n\n    /// An iterator visiting all key-value pairs, with mutable value references.\n    ///\n    /// The iterator order is arbitrary, but consistent across platforms for the\n    /// same crate version. Each key will be yielded once per associated value,\n    /// so if a key has 3 associated values, it will be yielded 3 times.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// map.insert(\"x-word\", \"hello\".parse().unwrap());\n    /// map.append(\"x-word\", \"goodbye\".parse().unwrap());\n    /// map.insert(\"x-number\", \"123\".parse().unwrap());\n    ///\n    /// for key_and_value in map.iter_mut() {\n    ///     match key_and_value {\n    ///         KeyAndMutValueRef::Ascii(key, mut value) =>\n    ///             value.set_sensitive(true),\n    ///         KeyAndMutValueRef::Binary(key, mut value) =>\n    ///             value.set_sensitive(false),\n    ///     }\n    /// }\n    /// ```\n    pub fn iter_mut(&mut self) -> IterMut<'_> {\n        IterMut {\n            inner: self.headers.iter_mut(),\n        }\n    }\n\n    /// An iterator visiting all keys.\n    ///\n    /// The iteration order is arbitrary, but consistent across platforms for\n    /// the same crate version. Each key will be yielded only once even if it\n    /// has multiple associated values.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// map.insert(\"x-word\", \"hello\".parse().unwrap());\n    /// map.append(\"x-word\", \"goodbye\".parse().unwrap());\n    /// map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n    ///\n    /// for key in map.keys() {\n    ///     match key {\n    ///         KeyRef::Ascii(ref key) =>\n    ///             println!(\"Ascii key: {:?}\", key),\n    ///         KeyRef::Binary(ref key) =>\n    ///             println!(\"Binary key: {:?}\", key),\n    ///     }\n    ///     println!(\"{:?}\", key);\n    /// }\n    /// ```\n    pub fn keys(&self) -> Keys<'_> {\n        Keys {\n            inner: self.headers.keys(),\n        }\n    }\n\n    /// An iterator visiting all values (both ascii and binary).\n    ///\n    /// The iteration order is arbitrary, but consistent across platforms for\n    /// the same crate version.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// map.insert(\"x-word\", \"hello\".parse().unwrap());\n    /// map.append(\"x-word\", \"goodbye\".parse().unwrap());\n    /// map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n    ///\n    /// for value in map.values() {\n    ///     match value {\n    ///         ValueRef::Ascii(ref value) =>\n    ///             println!(\"Ascii value: {:?}\", value),\n    ///         ValueRef::Binary(ref value) =>\n    ///             println!(\"Binary value: {:?}\", value),\n    ///     }\n    ///     println!(\"{:?}\", value);\n    /// }\n    /// ```\n    pub fn values(&self) -> Values<'_> {\n        Values {\n            inner: self.headers.iter(),\n        }\n    }\n\n    /// An iterator visiting all values mutably.\n    ///\n    /// The iteration order is arbitrary, but consistent across platforms for\n    /// the same crate version.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    ///\n    /// map.insert(\"x-word\", \"hello\".parse().unwrap());\n    /// map.append(\"x-word\", \"goodbye\".parse().unwrap());\n    /// map.insert(\"x-number\", \"123\".parse().unwrap());\n    ///\n    /// for value in map.values_mut() {\n    ///     match value {\n    ///         ValueRefMut::Ascii(mut value) =>\n    ///             value.set_sensitive(true),\n    ///         ValueRefMut::Binary(mut value) =>\n    ///             value.set_sensitive(false),\n    ///     }\n    /// }\n    /// ```\n    pub fn values_mut(&mut self) -> ValuesMut<'_> {\n        ValuesMut {\n            inner: self.headers.iter_mut(),\n        }\n    }\n\n    /// Gets the given ascii key's corresponding entry in the map for in-place\n    /// manipulation. For binary keys, use `entry_bin`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    ///\n    /// let headers = &[\n    ///     \"content-length\",\n    ///     \"x-hello\",\n    ///     \"Content-Length\",\n    ///     \"x-world\",\n    /// ];\n    ///\n    /// for &header in headers {\n    ///     let counter = map.entry(header).unwrap().or_insert(\"\".parse().unwrap());\n    ///     *counter = format!(\"{}{}\", counter.to_str().unwrap(), \"1\").parse().unwrap();\n    /// }\n    ///\n    /// assert_eq!(map.get(\"content-length\").unwrap(), \"11\");\n    /// assert_eq!(map.get(\"x-hello\").unwrap(), \"1\");\n    ///\n    /// // Gracefully handles parting invalid key strings\n    /// assert!(!map.entry(\"a{}b\").is_ok());\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append_bin(\"host-bin\", MetadataValue::from_bytes(b\"world\"));\n    /// assert!(!map.entry(\"host-bin\").is_ok());\n    /// assert!(!map.entry(\"host-bin\".to_string()).is_ok());\n    /// assert!(!map.entry(&(\"host-bin\".to_string())).is_ok());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(!map.entry(\"host{}\").is_ok());\n    /// assert!(!map.entry(\"host{}\".to_string()).is_ok());\n    /// assert!(!map.entry(&(\"host{}\".to_string())).is_ok());\n    /// ```\n    pub fn entry<K>(&mut self, key: K) -> Result<Entry<'_, Ascii>, InvalidMetadataKey>\n    where\n        K: AsMetadataKey<Ascii>,\n    {\n        self.generic_entry::<Ascii, K>(key)\n    }\n\n    /// Gets the given Binary key's corresponding entry in the map for in-place\n    /// manipulation.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// # use std::str;\n    /// let mut map = MetadataMap::default();\n    ///\n    /// let headers = &[\n    ///     \"content-length-bin\",\n    ///     \"x-hello-bin\",\n    ///     \"Content-Length-bin\",\n    ///     \"x-world-bin\",\n    /// ];\n    ///\n    /// for &header in headers {\n    ///     let counter = map.entry_bin(header).unwrap().or_insert(MetadataValue::from_bytes(b\"\"));\n    ///     *counter = MetadataValue::from_bytes(format!(\"{}{}\", str::from_utf8(counter.to_bytes().unwrap().as_ref()).unwrap(), \"1\").as_bytes());\n    /// }\n    ///\n    /// assert_eq!(map.get_bin(\"content-length-bin\").unwrap(), \"11\");\n    /// assert_eq!(map.get_bin(\"x-hello-bin\").unwrap(), \"1\");\n    ///\n    /// // Attempting to read a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append(\"host\", \"world\".parse().unwrap());\n    /// assert!(!map.entry_bin(\"host\").is_ok());\n    /// assert!(!map.entry_bin(\"host\".to_string()).is_ok());\n    /// assert!(!map.entry_bin(&(\"host\".to_string())).is_ok());\n    ///\n    /// // Attempting to read an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(!map.entry_bin(\"host{}-bin\").is_ok());\n    /// assert!(!map.entry_bin(\"host{}-bin\".to_string()).is_ok());\n    /// assert!(!map.entry_bin(&(\"host{}-bin\".to_string())).is_ok());\n    /// ```\n    pub fn entry_bin<K>(&mut self, key: K) -> Result<Entry<'_, Binary>, InvalidMetadataKey>\n    where\n        K: AsMetadataKey<Binary>,\n    {\n        self.generic_entry::<Binary, K>(key)\n    }\n\n    fn generic_entry<VE: ValueEncoding, K>(\n        &mut self,\n        key: K,\n    ) -> Result<Entry<'_, VE>, InvalidMetadataKey>\n    where\n        K: AsMetadataKey<VE>,\n    {\n        match key.entry(self) {\n            Ok(entry) => Ok(match entry {\n                http::header::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {\n                    inner: e,\n                    phantom: PhantomData,\n                }),\n                http::header::Entry::Vacant(e) => Entry::Vacant(VacantEntry {\n                    inner: e,\n                    phantom: PhantomData,\n                }),\n            }),\n            Err(err) => Err(err),\n        }\n    }\n\n    /// Inserts an ascii key-value pair into the map. To insert a binary entry,\n    /// use `insert_bin`.\n    ///\n    /// This method panics when the given key is a string and it cannot be\n    /// converted to a `MetadataKey<Ascii>`.\n    ///\n    /// If the map did not previously have this key present, then `None` is\n    /// returned.\n    ///\n    /// If the map did have this key present, the new value is associated with\n    /// the key and all previous values are removed. **Note** that only a single\n    /// one of the previous values is returned. If there are multiple values\n    /// that have been previously associated with the key, then the first one is\n    /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns\n    /// all values.\n    ///\n    /// The key is not updated, though; this matters for types that can be `==`\n    /// without being identical.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// assert!(map.insert(\"x-host\", \"world\".parse().unwrap()).is_none());\n    /// assert!(!map.is_empty());\n    ///\n    /// let mut prev = map.insert(\"x-host\", \"earth\".parse().unwrap()).unwrap();\n    /// assert_eq!(\"world\", prev);\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// // Trying to insert a key that is not valid panics.\n    /// map.insert(\"x{}host\", \"world\".parse().unwrap());\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// // Trying to insert a key that is binary panics (use insert_bin).\n    /// map.insert(\"x-host-bin\", \"world\".parse().unwrap());\n    /// ```\n    pub fn insert<K>(&mut self, key: K, val: MetadataValue<Ascii>) -> Option<MetadataValue<Ascii>>\n    where\n        K: IntoMetadataKey<Ascii>,\n    {\n        key.insert(self, val)\n    }\n\n    /// Like insert, but for Binary keys (for example \"trace-proto-bin\").\n    ///\n    /// This method panics when the given key is a string and it cannot be\n    /// converted to a `MetadataKey<Binary>`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// assert!(map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"world\")).is_none());\n    /// assert!(!map.is_empty());\n    ///\n    /// let mut prev = map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"earth\")).unwrap();\n    /// assert_eq!(\"world\", prev);\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    /// // Attempting to add a binary metadata entry with an invalid name\n    /// map.insert_bin(\"trace-proto\", MetadataValue::from_bytes(b\"hello\")); // This line panics!\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// // Trying to insert a key that is not valid panics.\n    /// map.insert_bin(\"x{}host-bin\", MetadataValue::from_bytes(b\"world\")); // This line panics!\n    /// ```\n    pub fn insert_bin<K>(\n        &mut self,\n        key: K,\n        val: MetadataValue<Binary>,\n    ) -> Option<MetadataValue<Binary>>\n    where\n        K: IntoMetadataKey<Binary>,\n    {\n        key.insert(self, val)\n    }\n\n    /// Inserts an ascii key-value pair into the map. To insert a binary entry,\n    /// use `append_bin`.\n    ///\n    /// This method panics when the given key is a string and it cannot be\n    /// converted to a `MetadataKey<Ascii>`.\n    ///\n    /// If the map did not previously have this key present, then `false` is\n    /// returned.\n    ///\n    /// If the map did have this key present, the new value is pushed to the end\n    /// of the list of values currently associated with the key. The key is not\n    /// updated, though; this matters for types that can be `==` without being\n    /// identical.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// assert!(map.insert(\"x-host\", \"world\".parse().unwrap()).is_none());\n    /// assert!(!map.is_empty());\n    ///\n    /// map.append(\"x-host\", \"earth\".parse().unwrap());\n    ///\n    /// let values = map.get_all(\"x-host\");\n    /// let mut i = values.iter();\n    /// assert_eq!(\"world\", *i.next().unwrap());\n    /// assert_eq!(\"earth\", *i.next().unwrap());\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// // Trying to append a key that is not valid panics.\n    /// map.append(\"x{}host\", \"world\".parse().unwrap()); // This line panics!\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// // Trying to append a key that is binary panics (use append_bin).\n    /// map.append(\"x-host-bin\", \"world\".parse().unwrap()); // This line panics!\n    /// ```\n    pub fn append<K>(&mut self, key: K, value: MetadataValue<Ascii>) -> bool\n    where\n        K: IntoMetadataKey<Ascii>,\n    {\n        key.append(self, value)\n    }\n\n    /// Like append, but for binary keys (for example \"trace-proto-bin\").\n    ///\n    /// This method panics when the given key is a string and it cannot be\n    /// converted to a `MetadataKey<Binary>`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// assert!(map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"world\")).is_none());\n    /// assert!(!map.is_empty());\n    ///\n    /// map.append_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"earth\"));\n    ///\n    /// let values = map.get_all_bin(\"trace-proto-bin\");\n    /// let mut i = values.iter();\n    /// assert_eq!(\"world\", *i.next().unwrap());\n    /// assert_eq!(\"earth\", *i.next().unwrap());\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// // Trying to append a key that is not valid panics.\n    /// map.append_bin(\"x{}host-bin\", MetadataValue::from_bytes(b\"world\")); // This line panics!\n    /// ```\n    ///\n    /// ```should_panic\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// // Trying to append a key that is ascii panics (use append).\n    /// map.append_bin(\"x-host\", MetadataValue::from_bytes(b\"world\")); // This line panics!\n    /// ```\n    pub fn append_bin<K>(&mut self, key: K, value: MetadataValue<Binary>) -> bool\n    where\n        K: IntoMetadataKey<Binary>,\n    {\n        key.append(self, value)\n    }\n\n    /// Removes an ascii key from the map, returning the value associated with\n    /// the key. To remove a binary key, use `remove_bin`.\n    ///\n    /// Returns `None` if the map does not contain the key. If there are\n    /// multiple values associated with the key, then the first one is returned.\n    /// See `remove_entry_mult` on `OccupiedEntry` for an API that yields all\n    /// values.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"x-host\", \"hello.world\".parse().unwrap());\n    ///\n    /// let prev = map.remove(\"x-host\").unwrap();\n    /// assert_eq!(\"hello.world\", prev);\n    ///\n    /// assert!(map.remove(\"x-host\").is_none());\n    ///\n    /// // Attempting to remove a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append_bin(\"host-bin\", MetadataValue::from_bytes(b\"world\"));\n    /// assert!(map.remove(\"host-bin\").is_none());\n    /// assert!(map.remove(\"host-bin\".to_string()).is_none());\n    /// assert!(map.remove(&(\"host-bin\".to_string())).is_none());\n    ///\n    /// // Attempting to remove an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.remove(\"host{}\").is_none());\n    /// assert!(map.remove(\"host{}\".to_string()).is_none());\n    /// assert!(map.remove(&(\"host{}\".to_string())).is_none());\n    /// ```\n    pub fn remove<K>(&mut self, key: K) -> Option<MetadataValue<Ascii>>\n    where\n        K: AsMetadataKey<Ascii>,\n    {\n        key.remove(self)\n    }\n\n    /// Like remove, but for Binary keys (for example \"trace-proto-bin\").\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert_bin(\"trace-proto-bin\", MetadataValue::from_bytes(b\"hello.world\"));\n    ///\n    /// let prev = map.remove_bin(\"trace-proto-bin\").unwrap();\n    /// assert_eq!(\"hello.world\", prev);\n    ///\n    /// assert!(map.remove_bin(\"trace-proto-bin\").is_none());\n    ///\n    /// // Attempting to remove a key of the wrong type fails by not\n    /// // finding anything.\n    /// map.append(\"host\", \"world\".parse().unwrap());\n    /// assert!(map.remove_bin(\"host\").is_none());\n    /// assert!(map.remove_bin(\"host\".to_string()).is_none());\n    /// assert!(map.remove_bin(&(\"host\".to_string())).is_none());\n    ///\n    /// // Attempting to remove an invalid key string fails by not\n    /// // finding anything.\n    /// assert!(map.remove_bin(\"host{}-bin\").is_none());\n    /// assert!(map.remove_bin(\"host{}-bin\".to_string()).is_none());\n    /// assert!(map.remove_bin(&(\"host{}-bin\".to_string())).is_none());\n    /// ```\n    pub fn remove_bin<K>(&mut self, key: K) -> Option<MetadataValue<Binary>>\n    where\n        K: AsMetadataKey<Binary>,\n    {\n        key.remove(self)\n    }\n\n    pub(crate) fn merge(&mut self, other: MetadataMap) {\n        self.headers.extend(other.headers);\n    }\n}\n\n// ===== impl Iter =====\n\nimpl<'a> Iterator for Iter<'a> {\n    type Item = KeyAndValueRef<'a>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.inner.next().map(|item| {\n            let (name, value) = item;\n            if Ascii::is_valid_key(name.as_str()) {\n                KeyAndValueRef::Ascii(\n                    MetadataKey::unchecked_from_header_name_ref(name),\n                    MetadataValue::unchecked_from_header_value_ref(value),\n                )\n            } else {\n                KeyAndValueRef::Binary(\n                    MetadataKey::unchecked_from_header_name_ref(name),\n                    MetadataValue::unchecked_from_header_value_ref(value),\n                )\n            }\n        })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\n// ===== impl IterMut =====\n\nimpl<'a> Iterator for IterMut<'a> {\n    type Item = KeyAndMutValueRef<'a>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.inner.next().map(|item| {\n            let (name, value) = item;\n            if Ascii::is_valid_key(name.as_str()) {\n                KeyAndMutValueRef::Ascii(\n                    MetadataKey::unchecked_from_header_name_ref(name),\n                    MetadataValue::unchecked_from_mut_header_value_ref(value),\n                )\n            } else {\n                KeyAndMutValueRef::Binary(\n                    MetadataKey::unchecked_from_header_name_ref(name),\n                    MetadataValue::unchecked_from_mut_header_value_ref(value),\n                )\n            }\n        })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\n// ===== impl ValueDrain =====\n\nimpl<VE: ValueEncoding> Iterator for ValueDrain<'_, VE> {\n    type Item = MetadataValue<VE>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.inner\n            .next()\n            .map(MetadataValue::unchecked_from_header_value)\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\n// ===== impl Keys =====\n\nimpl<'a> Iterator for Keys<'a> {\n    type Item = KeyRef<'a>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.inner.next().map(|key| {\n            if Ascii::is_valid_key(key.as_str()) {\n                KeyRef::Ascii(MetadataKey::unchecked_from_header_name_ref(key))\n            } else {\n                KeyRef::Binary(MetadataKey::unchecked_from_header_name_ref(key))\n            }\n        })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\nimpl ExactSizeIterator for Keys<'_> {}\n\n// ===== impl Values ====\n\nimpl<'a> Iterator for Values<'a> {\n    type Item = ValueRef<'a>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.inner.next().map(|item| {\n            let (name, value) = item;\n            if Ascii::is_valid_key(name.as_str()) {\n                ValueRef::Ascii(MetadataValue::unchecked_from_header_value_ref(value))\n            } else {\n                ValueRef::Binary(MetadataValue::unchecked_from_header_value_ref(value))\n            }\n        })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\n// ===== impl Values ====\n\nimpl<'a> Iterator for ValuesMut<'a> {\n    type Item = ValueRefMut<'a>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.inner.next().map(|item| {\n            let (name, value) = item;\n            if Ascii::is_valid_key(name.as_str()) {\n                ValueRefMut::Ascii(MetadataValue::unchecked_from_mut_header_value_ref(value))\n            } else {\n                ValueRefMut::Binary(MetadataValue::unchecked_from_mut_header_value_ref(value))\n            }\n        })\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\n// ===== impl ValueIter =====\n\nimpl<'a, VE: ValueEncoding> Iterator for ValueIter<'a, VE>\nwhere\n    VE: 'a,\n{\n    type Item = &'a MetadataValue<VE>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match self.inner {\n            Some(ref mut inner) => inner\n                .next()\n                .map(MetadataValue::unchecked_from_header_value_ref),\n            None => None,\n        }\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        match self.inner {\n            Some(ref inner) => inner.size_hint(),\n            None => (0, Some(0)),\n        }\n    }\n}\n\nimpl<'a, VE: ValueEncoding> DoubleEndedIterator for ValueIter<'a, VE>\nwhere\n    VE: 'a,\n{\n    fn next_back(&mut self) -> Option<Self::Item> {\n        match self.inner {\n            Some(ref mut inner) => inner\n                .next_back()\n                .map(MetadataValue::unchecked_from_header_value_ref),\n            None => None,\n        }\n    }\n}\n\n// ===== impl ValueIterMut =====\n\nimpl<'a, VE: ValueEncoding> Iterator for ValueIterMut<'a, VE>\nwhere\n    VE: 'a,\n{\n    type Item = &'a mut MetadataValue<VE>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.inner\n            .next()\n            .map(MetadataValue::unchecked_from_mut_header_value_ref)\n    }\n}\n\nimpl<'a, VE: ValueEncoding> DoubleEndedIterator for ValueIterMut<'a, VE>\nwhere\n    VE: 'a,\n{\n    fn next_back(&mut self) -> Option<Self::Item> {\n        self.inner\n            .next_back()\n            .map(MetadataValue::unchecked_from_mut_header_value_ref)\n    }\n}\n\n// ===== impl Entry =====\n\nimpl<'a, VE: ValueEncoding> Entry<'a, VE> {\n    /// Ensures a value is in the entry by inserting the default if empty.\n    ///\n    /// Returns a mutable reference to the **first** value in the entry.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map: MetadataMap = MetadataMap::default();\n    ///\n    /// let keys = &[\n    ///     \"content-length\",\n    ///     \"x-hello\",\n    ///     \"Content-Length\",\n    ///     \"x-world\",\n    /// ];\n    ///\n    /// for &key in keys {\n    ///     let counter = map.entry(key)\n    ///         .expect(\"valid key names\")\n    ///         .or_insert(\"\".parse().unwrap());\n    ///     *counter = format!(\"{}{}\", counter.to_str().unwrap(), \"1\").parse().unwrap();\n    /// }\n    ///\n    /// assert_eq!(map.get(\"content-length\").unwrap(), \"11\");\n    /// assert_eq!(map.get(\"x-hello\").unwrap(), \"1\");\n    /// ```\n    pub fn or_insert(self, default: MetadataValue<VE>) -> &'a mut MetadataValue<VE> {\n        use self::Entry::*;\n\n        match self {\n            Occupied(e) => e.into_mut(),\n            Vacant(e) => e.insert(default),\n        }\n    }\n\n    /// Ensures a value is in the entry by inserting the result of the default\n    /// function if empty.\n    ///\n    /// The default function is not called if the entry exists in the map.\n    /// Returns a mutable reference to the **first** value in the entry.\n    ///\n    /// # Examples\n    ///\n    /// Basic usage.\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// let res = map.entry(\"x-hello\").unwrap()\n    ///     .or_insert_with(|| \"world\".parse().unwrap());\n    ///\n    /// assert_eq!(res, \"world\");\n    /// ```\n    ///\n    /// The default function is not called if the entry exists in the map.\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    ///\n    /// let res = map.entry(\"host\")\n    ///     .expect(\"host is a valid string\")\n    ///     .or_insert_with(|| unreachable!());\n    ///\n    ///\n    /// assert_eq!(res, \"world\");\n    /// ```\n    pub fn or_insert_with<F: FnOnce() -> MetadataValue<VE>>(\n        self,\n        default: F,\n    ) -> &'a mut MetadataValue<VE> {\n        use self::Entry::*;\n\n        match self {\n            Occupied(e) => e.into_mut(),\n            Vacant(e) => e.insert(default()),\n        }\n    }\n\n    /// Returns a reference to the entry's key\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// assert_eq!(map.entry(\"x-hello\").unwrap().key(), \"x-hello\");\n    /// ```\n    pub fn key(&self) -> &MetadataKey<VE> {\n        use self::Entry::*;\n\n        MetadataKey::unchecked_from_header_name_ref(match *self {\n            Vacant(ref e) => e.inner.key(),\n            Occupied(ref e) => e.inner.key(),\n        })\n    }\n}\n\n// ===== impl VacantEntry =====\n\nimpl<'a, VE: ValueEncoding> VacantEntry<'a, VE> {\n    /// Returns a reference to the entry's key\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// assert_eq!(map.entry(\"x-hello\").unwrap().key(), \"x-hello\");\n    /// ```\n    pub fn key(&self) -> &MetadataKey<VE> {\n        MetadataKey::unchecked_from_header_name_ref(self.inner.key())\n    }\n\n    /// Take ownership of the key\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// if let Entry::Vacant(v) = map.entry(\"x-hello\").unwrap() {\n    ///     assert_eq!(v.into_key().as_str(), \"x-hello\");\n    /// }\n    /// ```\n    pub fn into_key(self) -> MetadataKey<VE> {\n        MetadataKey::unchecked_from_header_name(self.inner.into_key())\n    }\n\n    /// Insert the value into the entry.\n    ///\n    /// The value will be associated with this entry's key. A mutable reference\n    /// to the inserted value will be returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// if let Entry::Vacant(v) = map.entry(\"x-hello\").unwrap() {\n    ///     v.insert(\"world\".parse().unwrap());\n    /// }\n    ///\n    /// assert_eq!(map.get(\"x-hello\").unwrap(), \"world\");\n    /// ```\n    pub fn insert(self, value: MetadataValue<VE>) -> &'a mut MetadataValue<VE> {\n        MetadataValue::unchecked_from_mut_header_value_ref(self.inner.insert(value.inner))\n    }\n\n    /// Insert the value into the entry.\n    ///\n    /// The value will be associated with this entry's key. The new\n    /// `OccupiedEntry` is returned, allowing for further manipulation.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    ///\n    /// if let Entry::Vacant(v) = map.entry(\"x-hello\").unwrap() {\n    ///     let mut e = v.insert_entry(\"world\".parse().unwrap());\n    ///     e.insert(\"world2\".parse().unwrap());\n    /// }\n    ///\n    /// assert_eq!(map.get(\"x-hello\").unwrap(), \"world2\");\n    /// ```\n    pub fn insert_entry(self, value: MetadataValue<VE>) -> OccupiedEntry<'a, Ascii> {\n        OccupiedEntry {\n            inner: self.inner.insert_entry(value.inner),\n            phantom: PhantomData,\n        }\n    }\n}\n\n// ===== impl OccupiedEntry =====\n\nimpl<'a, VE: ValueEncoding> OccupiedEntry<'a, VE> {\n    /// Returns a reference to the entry's key.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(e) = map.entry(\"host\").unwrap() {\n    ///     assert_eq!(\"host\", e.key());\n    /// }\n    /// ```\n    pub fn key(&self) -> &MetadataKey<VE> {\n        MetadataKey::unchecked_from_header_name_ref(self.inner.key())\n    }\n\n    /// Get a reference to the first value in the entry.\n    ///\n    /// Values are stored in insertion order.\n    ///\n    /// # Panics\n    ///\n    /// `get` panics if there are no values associated with the entry.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"hello.world\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(mut e) = map.entry(\"host\").unwrap() {\n    ///     assert_eq!(e.get(), &\"hello.world\");\n    ///\n    ///     e.append(\"hello.earth\".parse().unwrap());\n    ///\n    ///     assert_eq!(e.get(), &\"hello.world\");\n    /// }\n    /// ```\n    pub fn get(&self) -> &MetadataValue<VE> {\n        MetadataValue::unchecked_from_header_value_ref(self.inner.get())\n    }\n\n    /// Get a mutable reference to the first value in the entry.\n    ///\n    /// Values are stored in insertion order.\n    ///\n    /// # Panics\n    ///\n    /// `get_mut` panics if there are no values associated with the entry.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    /// map.insert(\"host\", \"hello.world\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(mut e) = map.entry(\"host\").unwrap() {\n    ///     e.get_mut().set_sensitive(true);\n    ///     assert_eq!(e.get(), &\"hello.world\");\n    ///     assert!(e.get().is_sensitive());\n    /// }\n    /// ```\n    pub fn get_mut(&mut self) -> &mut MetadataValue<VE> {\n        MetadataValue::unchecked_from_mut_header_value_ref(self.inner.get_mut())\n    }\n\n    /// Converts the `OccupiedEntry` into a mutable reference to the **first**\n    /// value.\n    ///\n    /// The lifetime of the returned reference is bound to the original map.\n    ///\n    /// # Panics\n    ///\n    /// `into_mut` panics if there are no values associated with the entry.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    /// map.insert(\"host\", \"hello.world\".parse().unwrap());\n    /// map.append(\"host\", \"hello.earth\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(e) = map.entry(\"host\").unwrap() {\n    ///     e.into_mut().set_sensitive(true);\n    /// }\n    ///\n    /// assert!(map.get(\"host\").unwrap().is_sensitive());\n    /// ```\n    pub fn into_mut(self) -> &'a mut MetadataValue<VE> {\n        MetadataValue::unchecked_from_mut_header_value_ref(self.inner.into_mut())\n    }\n\n    /// Sets the value of the entry.\n    ///\n    /// All previous values associated with the entry are removed and the first\n    /// one is returned. See `insert_mult` for an API that returns all values.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"hello.world\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(mut e) = map.entry(\"host\").unwrap() {\n    ///     let mut prev = e.insert(\"earth\".parse().unwrap());\n    ///     assert_eq!(\"hello.world\", prev);\n    /// }\n    ///\n    /// assert_eq!(\"earth\", map.get(\"host\").unwrap());\n    /// ```\n    pub fn insert(&mut self, value: MetadataValue<VE>) -> MetadataValue<VE> {\n        let header_value = self.inner.insert(value.inner);\n        MetadataValue::unchecked_from_header_value(header_value)\n    }\n\n    /// Sets the value of the entry.\n    ///\n    /// This function does the same as `insert` except it returns an iterator\n    /// that yields all values previously associated with the key.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    /// map.append(\"host\", \"world2\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(mut e) = map.entry(\"host\").unwrap() {\n    ///     let mut prev = e.insert_mult(\"earth\".parse().unwrap());\n    ///     assert_eq!(\"world\", prev.next().unwrap());\n    ///     assert_eq!(\"world2\", prev.next().unwrap());\n    ///     assert!(prev.next().is_none());\n    /// }\n    ///\n    /// assert_eq!(\"earth\", map.get(\"host\").unwrap());\n    /// ```\n    pub fn insert_mult(&mut self, value: MetadataValue<VE>) -> ValueDrain<'_, VE> {\n        ValueDrain {\n            inner: self.inner.insert_mult(value.inner),\n            phantom: PhantomData,\n        }\n    }\n\n    /// Insert the value into the entry.\n    ///\n    /// The new value is appended to the end of the entry's value list. All\n    /// previous values associated with the entry are retained.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(mut e) = map.entry(\"host\").unwrap() {\n    ///     e.append(\"earth\".parse().unwrap());\n    /// }\n    ///\n    /// let values = map.get_all(\"host\");\n    /// let mut i = values.iter();\n    /// assert_eq!(\"world\", *i.next().unwrap());\n    /// assert_eq!(\"earth\", *i.next().unwrap());\n    /// ```\n    pub fn append(&mut self, value: MetadataValue<VE>) {\n        self.inner.append(value.inner)\n    }\n\n    /// Remove the entry from the map.\n    ///\n    /// All values associated with the entry are removed and the first one is\n    /// returned. See `remove_entry_mult` for an API that returns all values.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(e) = map.entry(\"host\").unwrap() {\n    ///     let mut prev = e.remove();\n    ///     assert_eq!(\"world\", prev);\n    /// }\n    ///\n    /// assert!(!map.contains_key(\"host\"));\n    /// ```\n    pub fn remove(self) -> MetadataValue<VE> {\n        let value = self.inner.remove();\n        MetadataValue::unchecked_from_header_value(value)\n    }\n\n    /// Remove the entry from the map.\n    ///\n    /// The key and all values associated with the entry are removed and the\n    /// first one is returned. See `remove_entry_mult` for an API that returns\n    /// all values.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(e) = map.entry(\"host\").unwrap() {\n    ///     let (key, mut prev) = e.remove_entry();\n    ///     assert_eq!(\"host\", key.as_str());\n    ///     assert_eq!(\"world\", prev);\n    /// }\n    ///\n    /// assert!(!map.contains_key(\"host\"));\n    /// ```\n    pub fn remove_entry(self) -> (MetadataKey<VE>, MetadataValue<VE>) {\n        let (name, value) = self.inner.remove_entry();\n        (\n            MetadataKey::unchecked_from_header_name(name),\n            MetadataValue::unchecked_from_header_value(value),\n        )\n    }\n\n    /// Remove the entry from the map.\n    ///\n    /// The key and all values associated with the entry are removed and\n    /// returned.\n    pub fn remove_entry_mult(self) -> (MetadataKey<VE>, ValueDrain<'a, VE>) {\n        let (name, value_drain) = self.inner.remove_entry_mult();\n        (\n            MetadataKey::unchecked_from_header_name(name),\n            ValueDrain {\n                inner: value_drain,\n                phantom: PhantomData,\n            },\n        )\n    }\n\n    /// Returns an iterator visiting all values associated with the entry.\n    ///\n    /// Values are iterated in insertion order.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    /// map.append(\"host\", \"earth\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(e) = map.entry(\"host\").unwrap() {\n    ///     let mut iter = e.iter();\n    ///     assert_eq!(&\"world\", iter.next().unwrap());\n    ///     assert_eq!(&\"earth\", iter.next().unwrap());\n    ///     assert!(iter.next().is_none());\n    /// }\n    /// ```\n    pub fn iter(&self) -> ValueIter<'_, VE> {\n        ValueIter {\n            inner: Some(self.inner.iter()),\n            phantom: PhantomData,\n        }\n    }\n\n    /// Returns an iterator mutably visiting all values associated with the\n    /// entry.\n    ///\n    /// Values are iterated in insertion order.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::default();\n    /// map.insert(\"host\", \"world\".parse().unwrap());\n    /// map.append(\"host\", \"earth\".parse().unwrap());\n    ///\n    /// if let Entry::Occupied(mut e) = map.entry(\"host\").unwrap() {\n    ///     for e in e.iter_mut() {\n    ///         e.set_sensitive(true);\n    ///     }\n    /// }\n    ///\n    /// let mut values = map.get_all(\"host\");\n    /// let mut i = values.iter();\n    /// assert!(i.next().unwrap().is_sensitive());\n    /// assert!(i.next().unwrap().is_sensitive());\n    /// ```\n    pub fn iter_mut(&mut self) -> ValueIterMut<'_, VE> {\n        ValueIterMut {\n            inner: self.inner.iter_mut(),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'a, VE: ValueEncoding> IntoIterator for OccupiedEntry<'a, VE>\nwhere\n    VE: 'a,\n{\n    type Item = &'a mut MetadataValue<VE>;\n    type IntoIter = ValueIterMut<'a, VE>;\n\n    fn into_iter(self) -> ValueIterMut<'a, VE> {\n        ValueIterMut {\n            inner: self.inner.into_iter(),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'a, 'b: 'a, VE: ValueEncoding> IntoIterator for &'b OccupiedEntry<'a, VE> {\n    type Item = &'a MetadataValue<VE>;\n    type IntoIter = ValueIter<'a, VE>;\n\n    fn into_iter(self) -> ValueIter<'a, VE> {\n        self.iter()\n    }\n}\n\nimpl<'a, 'b: 'a, VE: ValueEncoding> IntoIterator for &'b mut OccupiedEntry<'a, VE> {\n    type Item = &'a mut MetadataValue<VE>;\n    type IntoIter = ValueIterMut<'a, VE>;\n\n    fn into_iter(self) -> ValueIterMut<'a, VE> {\n        self.iter_mut()\n    }\n}\n\n// ===== impl GetAll =====\n\nimpl<'a, VE: ValueEncoding> GetAll<'a, VE> {\n    /// Returns an iterator visiting all values associated with the entry.\n    ///\n    /// Values are iterated in insertion order.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut map = MetadataMap::new();\n    /// map.insert(\"x-host\", \"hello.world\".parse().unwrap());\n    /// map.append(\"x-host\", \"hello.earth\".parse().unwrap());\n    ///\n    /// let values = map.get_all(\"x-host\");\n    /// let mut iter = values.iter();\n    /// assert_eq!(&\"hello.world\", iter.next().unwrap());\n    /// assert_eq!(&\"hello.earth\", iter.next().unwrap());\n    /// assert!(iter.next().is_none());\n    /// ```\n    pub fn iter(&self) -> ValueIter<'a, VE> {\n        ValueIter {\n            inner: self.inner.as_ref().map(|inner| inner.iter()),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq for GetAll<'_, VE> {\n    fn eq(&self, other: &Self) -> bool {\n        self.inner.iter().eq(other.inner.iter())\n    }\n}\n\nimpl<'a, VE: ValueEncoding> IntoIterator for GetAll<'a, VE>\nwhere\n    VE: 'a,\n{\n    type Item = &'a MetadataValue<VE>;\n    type IntoIter = ValueIter<'a, VE>;\n\n    fn into_iter(self) -> ValueIter<'a, VE> {\n        ValueIter {\n            inner: self.inner.map(|inner| inner.into_iter()),\n            phantom: PhantomData,\n        }\n    }\n}\n\nimpl<'a, 'b: 'a, VE: ValueEncoding> IntoIterator for &'b GetAll<'a, VE> {\n    type Item = &'a MetadataValue<VE>;\n    type IntoIter = ValueIter<'a, VE>;\n\n    fn into_iter(self) -> ValueIter<'a, VE> {\n        ValueIter {\n            inner: self.inner.as_ref().map(|inner| inner.into_iter()),\n            phantom: PhantomData,\n        }\n    }\n}\n\n// ===== impl IntoMetadataKey / AsMetadataKey =====\n\nmod into_metadata_key {\n    use super::{MetadataMap, MetadataValue, ValueEncoding};\n    use crate::metadata::key::MetadataKey;\n\n    /// A marker trait used to identify values that can be used as insert keys\n    /// to a `MetadataMap`.\n    pub trait IntoMetadataKey<VE: ValueEncoding>: Sealed<VE> {}\n\n    // All methods are on this pub(super) trait, instead of `IntoMetadataKey`,\n    // so that they aren't publicly exposed to the world.\n    //\n    // Being on the `IntoMetadataKey` trait would mean users could call\n    // `\"host\".insert(&mut map, \"localhost\")`.\n    //\n    // Ultimately, this allows us to adjust the signatures of these methods\n    // without breaking any external crate.\n    pub trait Sealed<VE: ValueEncoding> {\n        #[doc(hidden)]\n        fn insert(self, map: &mut MetadataMap, val: MetadataValue<VE>)\n        -> Option<MetadataValue<VE>>;\n\n        #[doc(hidden)]\n        fn append(self, map: &mut MetadataMap, val: MetadataValue<VE>) -> bool;\n    }\n\n    // ==== impls ====\n\n    impl<VE: ValueEncoding> Sealed<VE> for MetadataKey<VE> {\n        #[doc(hidden)]\n        #[inline]\n        fn insert(\n            self,\n            map: &mut MetadataMap,\n            val: MetadataValue<VE>,\n        ) -> Option<MetadataValue<VE>> {\n            map.headers\n                .insert(self.inner, val.inner)\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn append(self, map: &mut MetadataMap, val: MetadataValue<VE>) -> bool {\n            map.headers.append(self.inner, val.inner)\n        }\n    }\n\n    impl<VE: ValueEncoding> IntoMetadataKey<VE> for MetadataKey<VE> {}\n\n    impl<VE: ValueEncoding> Sealed<VE> for &MetadataKey<VE> {\n        #[doc(hidden)]\n        #[inline]\n        fn insert(\n            self,\n            map: &mut MetadataMap,\n            val: MetadataValue<VE>,\n        ) -> Option<MetadataValue<VE>> {\n            map.headers\n                .insert(&self.inner, val.inner)\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n        #[doc(hidden)]\n        #[inline]\n        fn append(self, map: &mut MetadataMap, val: MetadataValue<VE>) -> bool {\n            map.headers.append(&self.inner, val.inner)\n        }\n    }\n\n    impl<VE: ValueEncoding> IntoMetadataKey<VE> for &MetadataKey<VE> {}\n\n    impl<VE: ValueEncoding> Sealed<VE> for &'static str {\n        #[doc(hidden)]\n        #[inline]\n        fn insert(\n            self,\n            map: &mut MetadataMap,\n            val: MetadataValue<VE>,\n        ) -> Option<MetadataValue<VE>> {\n            // Perform name validation\n            let key = MetadataKey::<VE>::from_static(self);\n\n            map.headers\n                .insert(key.inner, val.inner)\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n        #[doc(hidden)]\n        #[inline]\n        fn append(self, map: &mut MetadataMap, val: MetadataValue<VE>) -> bool {\n            // Perform name validation\n            let key = MetadataKey::<VE>::from_static(self);\n\n            map.headers.append(key.inner, val.inner)\n        }\n    }\n\n    impl<VE: ValueEncoding> IntoMetadataKey<VE> for &'static str {}\n}\n\nmod as_metadata_key {\n    use super::{MetadataMap, MetadataValue, ValueEncoding};\n    use crate::metadata::key::{InvalidMetadataKey, MetadataKey};\n    use http::header::{Entry, GetAll, HeaderValue};\n\n    /// A marker trait used to identify values that can be used as search keys\n    /// to a `MetadataMap`.\n    pub trait AsMetadataKey<VE: ValueEncoding>: Sealed<VE> {}\n\n    // All methods are on this pub(super) trait, instead of `AsMetadataKey`,\n    // so that they aren't publicly exposed to the world.\n    //\n    // Being on the `AsMetadataKey` trait would mean users could call\n    // `\"host\".find(&map)`.\n    //\n    // Ultimately, this allows us to adjust the signatures of these methods\n    // without breaking any external crate.\n    pub trait Sealed<VE: ValueEncoding> {\n        #[doc(hidden)]\n        fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>>;\n\n        #[doc(hidden)]\n        fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue<VE>>;\n\n        #[doc(hidden)]\n        fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>>;\n\n        #[doc(hidden)]\n        fn entry(self, map: &mut MetadataMap)\n        -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey>;\n\n        #[doc(hidden)]\n        fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>>;\n    }\n\n    // ==== impls ====\n\n    impl<VE: ValueEncoding> Sealed<VE> for MetadataKey<VE> {\n        #[doc(hidden)]\n        #[inline]\n        fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> {\n            map.headers\n                .get(self.inner)\n                .map(MetadataValue::unchecked_from_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue<VE>> {\n            map.headers\n                .get_mut(self.inner)\n                .map(MetadataValue::unchecked_from_mut_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>> {\n            Some(map.headers.get_all(self.inner))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn entry(\n            self,\n            map: &mut MetadataMap,\n        ) -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey> {\n            Ok(map.headers.entry(self.inner))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>> {\n            map.headers\n                .remove(self.inner)\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n    }\n\n    impl<VE: ValueEncoding> AsMetadataKey<VE> for MetadataKey<VE> {}\n\n    impl<VE: ValueEncoding> Sealed<VE> for &MetadataKey<VE> {\n        #[doc(hidden)]\n        #[inline]\n        fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> {\n            map.headers\n                .get(&self.inner)\n                .map(MetadataValue::unchecked_from_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue<VE>> {\n            map.headers\n                .get_mut(&self.inner)\n                .map(MetadataValue::unchecked_from_mut_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>> {\n            Some(map.headers.get_all(&self.inner))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn entry(\n            self,\n            map: &mut MetadataMap,\n        ) -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey> {\n            Ok(map.headers.entry(&self.inner))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>> {\n            map.headers\n                .remove(&self.inner)\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n    }\n\n    impl<VE: ValueEncoding> AsMetadataKey<VE> for &MetadataKey<VE> {}\n\n    impl<VE: ValueEncoding> Sealed<VE> for &str {\n        #[doc(hidden)]\n        #[inline]\n        fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            map.headers\n                .get(self)\n                .map(MetadataValue::unchecked_from_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue<VE>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            map.headers\n                .get_mut(self)\n                .map(MetadataValue::unchecked_from_mut_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            Some(map.headers.get_all(self))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn entry(\n            self,\n            map: &mut MetadataMap,\n        ) -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey> {\n            if !VE::is_valid_key(self) {\n                return Err(InvalidMetadataKey::new());\n            }\n\n            let key = http::header::HeaderName::from_bytes(self.as_bytes())\n                .map_err(|_| InvalidMetadataKey::new())?;\n            let entry = map.headers.entry(key);\n            Ok(entry)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            map.headers\n                .remove(self)\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n    }\n\n    impl<VE: ValueEncoding> AsMetadataKey<VE> for &str {}\n\n    impl<VE: ValueEncoding> Sealed<VE> for String {\n        #[doc(hidden)]\n        #[inline]\n        fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> {\n            if !VE::is_valid_key(self.as_str()) {\n                return None;\n            }\n            map.headers\n                .get(self.as_str())\n                .map(MetadataValue::unchecked_from_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue<VE>> {\n            if !VE::is_valid_key(self.as_str()) {\n                return None;\n            }\n            map.headers\n                .get_mut(self.as_str())\n                .map(MetadataValue::unchecked_from_mut_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>> {\n            if !VE::is_valid_key(self.as_str()) {\n                return None;\n            }\n            Some(map.headers.get_all(self.as_str()))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn entry(\n            self,\n            map: &mut MetadataMap,\n        ) -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey> {\n            if !VE::is_valid_key(self.as_str()) {\n                return Err(InvalidMetadataKey::new());\n            }\n\n            let key = http::header::HeaderName::from_bytes(self.as_bytes())\n                .map_err(|_| InvalidMetadataKey::new())?;\n            Ok(map.headers.entry(key))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>> {\n            if !VE::is_valid_key(self.as_str()) {\n                return None;\n            }\n            map.headers\n                .remove(self.as_str())\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n    }\n\n    impl<VE: ValueEncoding> AsMetadataKey<VE> for String {}\n\n    impl<VE: ValueEncoding> Sealed<VE> for &String {\n        #[doc(hidden)]\n        #[inline]\n        fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            map.headers\n                .get(self.as_str())\n                .map(MetadataValue::unchecked_from_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue<VE>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            map.headers\n                .get_mut(self.as_str())\n                .map(MetadataValue::unchecked_from_mut_header_value_ref)\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            Some(map.headers.get_all(self.as_str()))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn entry(\n            self,\n            map: &mut MetadataMap,\n        ) -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey> {\n            if !VE::is_valid_key(self) {\n                return Err(InvalidMetadataKey::new());\n            }\n\n            let key = http::header::HeaderName::from_bytes(self.as_bytes())\n                .map_err(|_| InvalidMetadataKey::new())?;\n            Ok(map.headers.entry(key))\n        }\n\n        #[doc(hidden)]\n        #[inline]\n        fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>> {\n            if !VE::is_valid_key(self) {\n                return None;\n            }\n            map.headers\n                .remove(self.as_str())\n                .map(MetadataValue::unchecked_from_header_value)\n        }\n    }\n\n    impl<VE: ValueEncoding> AsMetadataKey<VE> for &String {}\n}\n\nmod as_encoding_agnostic_metadata_key {\n    use super::{MetadataMap, ValueEncoding};\n    use crate::metadata::key::MetadataKey;\n\n    /// A marker trait used to identify values that can be used as search keys\n    /// to a `MetadataMap`, for operations that don't expose the actual value.\n    pub trait AsEncodingAgnosticMetadataKey: Sealed {}\n\n    // All methods are on this pub(super) trait, instead of\n    // `AsEncodingAgnosticMetadataKey`, so that they aren't publicly exposed to\n    // the world.\n    //\n    // Being on the `AsEncodingAgnosticMetadataKey` trait would mean users could\n    // call `\"host\".contains_key(&map)`.\n    //\n    // Ultimately, this allows us to adjust the signatures of these methods\n    // without breaking any external crate.\n    pub trait Sealed {\n        #[doc(hidden)]\n        fn contains_key(&self, map: &MetadataMap) -> bool;\n    }\n\n    // ==== impls ====\n\n    impl<VE: ValueEncoding> Sealed for MetadataKey<VE> {\n        #[doc(hidden)]\n        #[inline]\n        fn contains_key(&self, map: &MetadataMap) -> bool {\n            map.headers.contains_key(&self.inner)\n        }\n    }\n\n    impl<VE: ValueEncoding> AsEncodingAgnosticMetadataKey for MetadataKey<VE> {}\n\n    impl<VE: ValueEncoding> Sealed for &MetadataKey<VE> {\n        #[doc(hidden)]\n        #[inline]\n        fn contains_key(&self, map: &MetadataMap) -> bool {\n            map.headers.contains_key(&self.inner)\n        }\n    }\n\n    impl<VE: ValueEncoding> AsEncodingAgnosticMetadataKey for &MetadataKey<VE> {}\n\n    impl Sealed for &str {\n        #[doc(hidden)]\n        #[inline]\n        fn contains_key(&self, map: &MetadataMap) -> bool {\n            map.headers.contains_key(*self)\n        }\n    }\n\n    impl AsEncodingAgnosticMetadataKey for &str {}\n\n    impl Sealed for String {\n        #[doc(hidden)]\n        #[inline]\n        fn contains_key(&self, map: &MetadataMap) -> bool {\n            map.headers.contains_key(self.as_str())\n        }\n    }\n\n    impl AsEncodingAgnosticMetadataKey for String {}\n\n    impl Sealed for &String {\n        #[doc(hidden)]\n        #[inline]\n        fn contains_key(&self, map: &MetadataMap) -> bool {\n            map.headers.contains_key(self.as_str())\n        }\n    }\n\n    impl AsEncodingAgnosticMetadataKey for &String {}\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_from_headers_takes_http_headers() {\n        let mut http_map = http::HeaderMap::new();\n        http_map.insert(\"x-host\", \"example.com\".parse().unwrap());\n\n        let map = MetadataMap::from_headers(http_map);\n\n        assert_eq!(map.get(\"x-host\").unwrap(), \"example.com\");\n    }\n\n    #[test]\n    fn test_to_headers_encoding() {\n        use crate::Status;\n        let special_char_message = \"Beyond 100% ascii \\t\\n\\r🌶️💉💧🐮🍺\";\n        let s1 = Status::unknown(special_char_message);\n\n        assert_eq!(s1.message(), special_char_message);\n\n        let s1_map = s1.to_header_map().unwrap();\n        let s2 = Status::from_header_map(&s1_map).unwrap();\n\n        assert_eq!(s1.message(), s2.message());\n\n        assert!(\n            s1_map\n                .get(\"grpc-message\")\n                .unwrap()\n                .to_str()\n                .unwrap()\n                .starts_with(\"Beyond%20100%25%20ascii\"),\n            \"Percent sign or other character isn't encoded as desired: {:?}\",\n            s1_map.get(\"grpc-message\")\n        );\n    }\n\n    #[test]\n    fn test_iter_categorizes_ascii_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n        map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n\n        let mut found_x_word = false;\n        for key_and_value in map.iter() {\n            if let KeyAndValueRef::Ascii(key, _value) = key_and_value {\n                if key.as_str() == \"x-word\" {\n                    found_x_word = true;\n                } else {\n                    panic!(\"Unexpected key\");\n                }\n            }\n        }\n        assert!(found_x_word);\n    }\n\n    #[test]\n    fn test_iter_categorizes_binary_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n\n        let mut found_x_word_bin = false;\n        for key_and_value in map.iter() {\n            if let KeyAndValueRef::Binary(key, _value) = key_and_value {\n                if key.as_str() == \"x-word-bin\" {\n                    found_x_word_bin = true;\n                } else {\n                    panic!(\"Unexpected key\");\n                }\n            }\n        }\n        assert!(found_x_word_bin);\n    }\n\n    #[test]\n    fn test_iter_mut_categorizes_ascii_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n        map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n\n        let mut found_x_word = false;\n        for key_and_value in map.iter_mut() {\n            if let KeyAndMutValueRef::Ascii(key, _value) = key_and_value {\n                if key.as_str() == \"x-word\" {\n                    found_x_word = true;\n                } else {\n                    panic!(\"Unexpected key\");\n                }\n            }\n        }\n        assert!(found_x_word);\n    }\n\n    #[test]\n    fn test_iter_mut_categorizes_binary_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n\n        let mut found_x_word_bin = false;\n        for key_and_value in map.iter_mut() {\n            if let KeyAndMutValueRef::Binary(key, _value) = key_and_value {\n                if key.as_str() == \"x-word-bin\" {\n                    found_x_word_bin = true;\n                } else {\n                    panic!(\"Unexpected key\");\n                }\n            }\n        }\n        assert!(found_x_word_bin);\n    }\n\n    #[test]\n    fn test_keys_categorizes_ascii_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n        map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n\n        let mut found_x_word = false;\n        for key in map.keys() {\n            if let KeyRef::Ascii(key) = key {\n                if key.as_str() == \"x-word\" {\n                    found_x_word = true;\n                } else {\n                    panic!(\"Unexpected key\");\n                }\n            }\n        }\n        assert!(found_x_word);\n    }\n\n    #[test]\n    fn test_keys_categorizes_binary_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n\n        let mut found_x_number_bin = false;\n        for key in map.keys() {\n            if let KeyRef::Binary(key) = key {\n                if key.as_str() == \"x-number-bin\" {\n                    found_x_number_bin = true;\n                } else {\n                    panic!(\"Unexpected key\");\n                }\n            }\n        }\n        assert!(found_x_number_bin);\n    }\n\n    #[test]\n    fn test_values_categorizes_ascii_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n        map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n\n        let mut found_x_word = false;\n        for value in map.values() {\n            if let ValueRef::Ascii(value) = value {\n                if *value == \"hello\" {\n                    found_x_word = true;\n                } else {\n                    panic!(\"Unexpected key\");\n                }\n            }\n        }\n        assert!(found_x_word);\n    }\n\n    #[test]\n    fn test_values_categorizes_binary_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n\n        let mut found_x_word_bin = false;\n        for value_ref in map.values() {\n            if let ValueRef::Binary(value) = value_ref {\n                assert_eq!(*value, \"goodbye\");\n                found_x_word_bin = true;\n            }\n        }\n        assert!(found_x_word_bin);\n    }\n\n    #[test]\n    fn test_values_mut_categorizes_ascii_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n        map.insert_bin(\"x-number-bin\", MetadataValue::from_bytes(b\"123\"));\n\n        let mut found_x_word = false;\n        for value_ref in map.values_mut() {\n            if let ValueRefMut::Ascii(value) = value_ref {\n                assert_eq!(*value, \"hello\");\n                found_x_word = true;\n            }\n        }\n        assert!(found_x_word);\n    }\n\n    #[test]\n    fn test_values_mut_categorizes_binary_entries() {\n        let mut map = MetadataMap::new();\n\n        map.insert(\"x-word\", \"hello\".parse().unwrap());\n        map.append_bin(\"x-word-bin\", MetadataValue::from_bytes(b\"goodbye\"));\n\n        let mut found_x_word_bin = false;\n        for value in map.values_mut() {\n            if let ValueRefMut::Binary(value) = value {\n                assert_eq!(*value, \"goodbye\");\n                found_x_word_bin = true;\n            }\n        }\n        assert!(found_x_word_bin);\n    }\n\n    #[allow(dead_code)]\n    fn value_drain_is_send_sync() {\n        fn is_send_sync<T: Send + Sync>() {}\n\n        is_send_sync::<Iter<'_>>();\n        is_send_sync::<IterMut<'_>>();\n\n        is_send_sync::<ValueDrain<'_, Ascii>>();\n        is_send_sync::<ValueDrain<'_, Binary>>();\n\n        is_send_sync::<ValueIterMut<'_, Ascii>>();\n        is_send_sync::<ValueIterMut<'_, Binary>>();\n    }\n}\n"
  },
  {
    "path": "tonic/src/metadata/mod.rs",
    "content": "//! Contains data structures and utilities for handling gRPC custom metadata.\n\nmod encoding;\nmod key;\nmod map;\nmod value;\n\npub use self::encoding::Ascii;\npub use self::encoding::Binary;\npub use self::key::AsciiMetadataKey;\npub use self::key::BinaryMetadataKey;\npub use self::key::MetadataKey;\npub use self::map::Entry;\npub use self::map::GetAll;\npub use self::map::Iter;\npub use self::map::IterMut;\npub use self::map::KeyAndMutValueRef;\npub use self::map::KeyAndValueRef;\npub use self::map::KeyRef;\npub use self::map::Keys;\npub use self::map::MetadataMap;\npub use self::map::OccupiedEntry;\npub use self::map::VacantEntry;\npub use self::map::ValueDrain;\npub use self::map::ValueIter;\npub use self::map::ValueRef;\npub use self::map::ValueRefMut;\npub use self::map::Values;\npub use self::map::ValuesMut;\npub use self::value::AsciiMetadataValue;\npub use self::value::BinaryMetadataValue;\npub use self::value::MetadataValue;\nuse http::HeaderValue;\n\npub(crate) use self::map::GRPC_TIMEOUT_HEADER;\n\n/// HTTP Header `content-type` value for gRPC calls.\npub const GRPC_CONTENT_TYPE: HeaderValue = HeaderValue::from_static(\"application/grpc\");\n\n/// The metadata::errors module contains types for errors that can occur\n/// while handling gRPC custom metadata.\npub mod errors {\n    pub use super::encoding::InvalidMetadataValue;\n    pub use super::encoding::InvalidMetadataValueBytes;\n    pub use super::key::InvalidMetadataKey;\n    pub use super::value::ToStrError;\n}\n"
  },
  {
    "path": "tonic/src/metadata/value.rs",
    "content": "use super::encoding::{\n    Ascii, Binary, InvalidMetadataValue, InvalidMetadataValueBytes, ValueEncoding,\n};\nuse super::key::MetadataKey;\n\nuse bytes::Bytes;\nuse http::header::HeaderValue;\nuse std::error::Error;\nuse std::hash::{Hash, Hasher};\nuse std::marker::PhantomData;\nuse std::str::FromStr;\nuse std::{cmp, fmt};\n\n/// Represents a custom metadata field value.\n///\n/// `MetadataValue` is used as the [`MetadataMap`] value.\n///\n/// [`HeaderMap`]: struct.HeaderMap.html\n/// [`MetadataMap`]: struct.MetadataMap.html\n#[derive(Clone)]\n#[repr(transparent)]\npub struct MetadataValue<VE: ValueEncoding> {\n    // Note: There are unsafe transmutes that assume that the memory layout\n    // of MetadataValue is identical to HeaderValue\n    pub(crate) inner: HeaderValue,\n    phantom: PhantomData<VE>,\n}\n\n/// A possible error when converting a `MetadataValue` to a string representation.\n///\n/// Metadata field values may contain opaque bytes, in which case it is not\n/// possible to represent the value as a string.\n#[derive(Debug)]\npub struct ToStrError {\n    _priv: (),\n}\n\n/// An ascii metadata value.\npub type AsciiMetadataValue = MetadataValue<Ascii>;\n/// A binary metadata value.\npub type BinaryMetadataValue = MetadataValue<Binary>;\n\nimpl<VE: ValueEncoding> MetadataValue<VE> {\n    /// Convert a static string to a `MetadataValue`.\n    ///\n    /// This function will not perform any copying, however the string is\n    /// checked to ensure that no invalid characters are present.\n    ///\n    /// For Ascii values, only visible ASCII characters (32-127) are permitted.\n    /// For Binary values, the string must be valid base64.\n    ///\n    /// # Panics\n    ///\n    /// This function panics if the argument contains invalid metadata value\n    /// characters.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_static(\"hello\");\n    /// assert_eq!(val, \"hello\");\n    /// ```\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = BinaryMetadataValue::from_static(\"SGVsbG8hIQ==\");\n    /// assert_eq!(val, \"Hello!!\");\n    /// ```\n    #[inline]\n    pub fn from_static(src: &'static str) -> Self {\n        MetadataValue {\n            inner: VE::from_static(src),\n            phantom: PhantomData,\n        }\n    }\n\n    /// Convert a `Bytes` directly into a `MetadataValue` without validating.\n    /// For `MetadataValue<Binary>` the provided parameter must be base64\n    /// encoded without padding bytes at the end.\n    ///\n    /// # Safety\n    ///\n    /// This function does NOT validate that illegal bytes are not contained\n    /// within the buffer.\n    #[inline]\n    pub unsafe fn from_shared_unchecked(src: Bytes) -> Self {\n        unsafe {\n            MetadataValue {\n                inner: HeaderValue::from_maybe_shared_unchecked(src),\n                phantom: PhantomData,\n            }\n        }\n    }\n\n    /// Returns true if the `MetadataValue` has a length of zero bytes.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_static(\"\");\n    /// assert!(val.is_empty());\n    ///\n    /// let val = AsciiMetadataValue::from_static(\"hello\");\n    /// assert!(!val.is_empty());\n    /// ```\n    #[inline]\n    pub fn is_empty(&self) -> bool {\n        VE::is_empty(self.inner.as_bytes())\n    }\n\n    /// Converts a `MetadataValue` to a Bytes buffer. This method cannot\n    /// fail for Ascii values. For Ascii values, `as_bytes` is more convenient\n    /// to use.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_static(\"hello\");\n    /// assert_eq!(val.to_bytes().unwrap().as_ref(), b\"hello\");\n    /// ```\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = BinaryMetadataValue::from_bytes(b\"hello\");\n    /// assert_eq!(val.to_bytes().unwrap().as_ref(), b\"hello\");\n    /// ```\n    #[inline]\n    pub fn to_bytes(&self) -> Result<Bytes, InvalidMetadataValueBytes> {\n        VE::decode(self.inner.as_bytes())\n    }\n\n    /// Mark that the metadata value represents sensitive information.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut val = AsciiMetadataValue::from_static(\"my secret\");\n    ///\n    /// val.set_sensitive(true);\n    /// assert!(val.is_sensitive());\n    ///\n    /// val.set_sensitive(false);\n    /// assert!(!val.is_sensitive());\n    /// ```\n    #[inline]\n    pub fn set_sensitive(&mut self, val: bool) {\n        self.inner.set_sensitive(val);\n    }\n\n    /// Returns `true` if the value represents sensitive data.\n    ///\n    /// Sensitive data could represent passwords or other data that should not\n    /// be stored on disk or in memory. This setting can be used by components\n    /// like caches to avoid storing the value. HPACK encoders must set the\n    /// metadata field to never index when `is_sensitive` returns true.\n    ///\n    /// Note that sensitivity is not factored into equality or ordering.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let mut val = AsciiMetadataValue::from_static(\"my secret\");\n    ///\n    /// val.set_sensitive(true);\n    /// assert!(val.is_sensitive());\n    ///\n    /// val.set_sensitive(false);\n    /// assert!(!val.is_sensitive());\n    /// ```\n    #[inline]\n    pub fn is_sensitive(&self) -> bool {\n        self.inner.is_sensitive()\n    }\n\n    /// Converts a `MetadataValue` to a byte slice. For Binary values, the\n    /// return value is base64 encoded.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_static(\"hello\");\n    /// assert_eq!(val.as_encoded_bytes(), b\"hello\");\n    /// ```\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = BinaryMetadataValue::from_bytes(b\"Hello!\");\n    /// assert_eq!(val.as_encoded_bytes(), b\"SGVsbG8h\");\n    /// ```\n    #[inline]\n    pub fn as_encoded_bytes(&self) -> &[u8] {\n        self.inner.as_bytes()\n    }\n\n    /// Converts a HeaderValue to a MetadataValue. This method assumes that the\n    /// caller has made sure that the value is of the correct Ascii or Binary\n    /// value encoding.\n    #[inline]\n    pub(crate) fn unchecked_from_header_value(value: HeaderValue) -> Self {\n        MetadataValue {\n            inner: value,\n            phantom: PhantomData,\n        }\n    }\n\n    /// Converts a HeaderValue reference to a MetadataValue. This method assumes\n    /// that the caller has made sure that the value is of the correct Ascii or\n    /// Binary value encoding.\n    #[inline]\n    pub(crate) fn unchecked_from_header_value_ref(header_value: &HeaderValue) -> &Self {\n        unsafe { &*(header_value as *const HeaderValue as *const Self) }\n    }\n\n    /// Converts a HeaderValue reference to a MetadataValue. This method assumes\n    /// that the caller has made sure that the value is of the correct Ascii or\n    /// Binary value encoding.\n    #[inline]\n    pub(crate) fn unchecked_from_mut_header_value_ref(header_value: &mut HeaderValue) -> &mut Self {\n        unsafe { &mut *(header_value as *mut HeaderValue as *mut Self) }\n    }\n}\n\n/// Attempt to convert a byte slice to a `MetadataValue`.\n///\n/// For Ascii metadata values, If the argument contains invalid metadata\n/// value bytes, an error is returned. Only byte values between 32 and 255\n/// (inclusive) are permitted, excluding byte 127 (DEL).\n///\n/// For Binary metadata values this method cannot fail. See also the Binary\n/// only version of this method `from_bytes`.\n///\n/// # Examples\n///\n/// ```\n/// # use tonic::metadata::*;\n/// let val = AsciiMetadataValue::try_from(b\"hello\\xfa\").unwrap();\n/// assert_eq!(val, &b\"hello\\xfa\"[..]);\n/// ```\n///\n/// An invalid value\n///\n/// ```\n/// # use tonic::metadata::*;\n/// let val = AsciiMetadataValue::try_from(b\"\\n\");\n/// assert!(val.is_err());\n/// ```\nimpl<VE: ValueEncoding> TryFrom<&[u8]> for MetadataValue<VE> {\n    type Error = InvalidMetadataValueBytes;\n\n    #[inline]\n    fn try_from(src: &[u8]) -> Result<Self, Self::Error> {\n        VE::from_bytes(src).map(|value| MetadataValue {\n            inner: value,\n            phantom: PhantomData,\n        })\n    }\n}\n\n/// Attempt to convert a byte slice to a `MetadataValue`.\n///\n/// For Ascii metadata values, If the argument contains invalid metadata\n/// value bytes, an error is returned. Only byte values between 32 and 255\n/// (inclusive) are permitted, excluding byte 127 (DEL).\n///\n/// For Binary metadata values this method cannot fail. See also the Binary\n/// only version of this method `from_bytes`.\n///\n/// # Examples\n///\n/// ```\n/// # use tonic::metadata::*;\n/// let val = AsciiMetadataValue::try_from(b\"hello\\xfa\").unwrap();\n/// assert_eq!(val, &b\"hello\\xfa\"[..]);\n/// ```\n///\n/// An invalid value\n///\n/// ```\n/// # use tonic::metadata::*;\n/// let val = AsciiMetadataValue::try_from(b\"\\n\");\n/// assert!(val.is_err());\n/// ```\nimpl<VE: ValueEncoding, const N: usize> TryFrom<&[u8; N]> for MetadataValue<VE> {\n    type Error = InvalidMetadataValueBytes;\n\n    #[inline]\n    fn try_from(src: &[u8; N]) -> Result<Self, Self::Error> {\n        Self::try_from(src.as_ref())\n    }\n}\n\n/// Attempt to convert a `Bytes` buffer to a `MetadataValue`.\n///\n/// For `MetadataValue<Ascii>`, if the argument contains invalid metadata\n/// value bytes, an error is returned. Only byte values between 32 and 255\n/// (inclusive) are permitted, excluding byte 127 (DEL).\n///\n/// For `MetadataValue<Binary>`, if the argument is not valid base64, an\n/// error is returned. In use cases where the input is not base64 encoded,\n/// use `from_bytes`; if the value has to be encoded it's not possible to\n/// share the memory anyways.\nimpl<VE: ValueEncoding> TryFrom<Bytes> for MetadataValue<VE> {\n    type Error = InvalidMetadataValueBytes;\n\n    #[inline]\n    fn try_from(src: Bytes) -> Result<Self, Self::Error> {\n        VE::from_shared(src).map(|value| MetadataValue {\n            inner: value,\n            phantom: PhantomData,\n        })\n    }\n}\n\n/// Attempt to convert a Vec of bytes to a `MetadataValue`.\n///\n/// For `MetadataValue<Ascii>`, if the argument contains invalid metadata\n/// value bytes, an error is returned. Only byte values between 32 and 255\n/// (inclusive) are permitted, excluding byte 127 (DEL).\n///\n/// For `MetadataValue<Binary>`, if the argument is not valid base64, an\n/// error is returned. In use cases where the input is not base64 encoded,\n/// use `from_bytes`; if the value has to be encoded it's not possible to\n/// share the memory anyways.\nimpl<VE: ValueEncoding> TryFrom<Vec<u8>> for MetadataValue<VE> {\n    type Error = InvalidMetadataValueBytes;\n\n    #[inline]\n    fn try_from(src: Vec<u8>) -> Result<Self, Self::Error> {\n        Self::try_from(src.as_slice())\n    }\n}\n\n/// Attempt to convert a string to a `MetadataValue<Ascii>`.\n///\n/// If the argument contains invalid metadata value characters, an error is\n/// returned. Only visible ASCII characters (32-127) are permitted. Use\n/// `from_bytes` to create a `MetadataValue` that includes opaque octets\n/// (128-255).\nimpl<'a> TryFrom<&'a str> for MetadataValue<Ascii> {\n    type Error = InvalidMetadataValue;\n\n    #[inline]\n    fn try_from(s: &'a str) -> Result<Self, Self::Error> {\n        s.parse()\n    }\n}\n\n/// Attempt to convert a string to a `MetadataValue<Ascii>`.\n///\n/// If the argument contains invalid metadata value characters, an error is\n/// returned. Only visible ASCII characters (32-127) are permitted. Use\n/// `from_bytes` to create a `MetadataValue` that includes opaque octets\n/// (128-255).\nimpl<'a> TryFrom<&'a String> for MetadataValue<Ascii> {\n    type Error = InvalidMetadataValue;\n\n    #[inline]\n    fn try_from(s: &'a String) -> Result<Self, Self::Error> {\n        s.parse()\n    }\n}\n\n/// Attempt to convert a string to a `MetadataValue<Ascii>`.\n///\n/// If the argument contains invalid metadata value characters, an error is\n/// returned. Only visible ASCII characters (32-127) are permitted. Use\n/// `from_bytes` to create a `MetadataValue` that includes opaque octets\n/// (128-255).\nimpl TryFrom<String> for MetadataValue<Ascii> {\n    type Error = InvalidMetadataValue;\n\n    #[inline]\n    fn try_from(s: String) -> Result<Self, Self::Error> {\n        s.parse()\n    }\n}\n\nimpl MetadataValue<Ascii> {\n    /// Converts a MetadataKey into a `MetadataValue<Ascii>`.\n    ///\n    /// Since every valid MetadataKey is a valid MetadataValue this is done\n    /// infallibly.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_key::<Ascii>(\"accept\".parse().unwrap());\n    /// assert_eq!(val, AsciiMetadataValue::try_from(b\"accept\").unwrap());\n    /// ```\n    #[inline]\n    pub fn from_key<KeyVE: ValueEncoding>(key: MetadataKey<KeyVE>) -> Self {\n        key.into()\n    }\n\n    /// Returns the length of `self`, in bytes.\n    ///\n    /// This method is not available for `MetadataValue<Binary>` because that\n    /// cannot be implemented in constant time, which most people would probably\n    /// expect. To get the length of `MetadataValue<Binary>`, convert it to a\n    /// Bytes value and measure its length.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_static(\"hello\");\n    /// assert_eq!(val.len(), 5);\n    /// ```\n    #[inline]\n    pub fn len(&self) -> usize {\n        self.inner.len()\n    }\n\n    /// Yields a `&str` slice if the `MetadataValue` only contains visible ASCII\n    /// chars.\n    ///\n    /// This function will perform a scan of the metadata value, checking all the\n    /// characters.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_static(\"hello\");\n    /// assert_eq!(val.to_str().unwrap(), \"hello\");\n    /// ```\n    pub fn to_str(&self) -> Result<&str, ToStrError> {\n        self.inner.to_str().map_err(|_| ToStrError::new())\n    }\n\n    /// Converts a `MetadataValue` to a byte slice. For Binary values, use\n    /// `to_bytes`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = AsciiMetadataValue::from_static(\"hello\");\n    /// assert_eq!(val.as_bytes(), b\"hello\");\n    /// ```\n    #[inline]\n    pub fn as_bytes(&self) -> &[u8] {\n        self.inner.as_bytes()\n    }\n}\n\nimpl MetadataValue<Binary> {\n    /// Convert a byte slice to a `MetadataValue<Binary>`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic::metadata::*;\n    /// let val = BinaryMetadataValue::from_bytes(b\"hello\\xfa\");\n    /// assert_eq!(val, &b\"hello\\xfa\"[..]);\n    /// ```\n    #[inline]\n    pub fn from_bytes(src: &[u8]) -> Self {\n        // Only the Ascii version of try_from can fail.\n        Self::try_from(src).unwrap()\n    }\n}\n\nimpl<VE: ValueEncoding> AsRef<[u8]> for MetadataValue<VE> {\n    #[inline]\n    fn as_ref(&self) -> &[u8] {\n        self.inner.as_ref()\n    }\n}\n\nimpl<VE: ValueEncoding> fmt::Debug for MetadataValue<VE> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        VE::fmt(&self.inner, f)\n    }\n}\n\nimpl<KeyVE: ValueEncoding> From<MetadataKey<KeyVE>> for MetadataValue<Ascii> {\n    #[inline]\n    fn from(h: MetadataKey<KeyVE>) -> MetadataValue<Ascii> {\n        MetadataValue {\n            inner: h.inner.into(),\n            phantom: PhantomData,\n        }\n    }\n}\n\nmacro_rules! from_integers {\n    ($($name:ident: $t:ident => $max_len:expr),*) => {$(\n        impl From<$t> for MetadataValue<Ascii> {\n            fn from(num: $t) -> MetadataValue<Ascii> {\n                MetadataValue {\n                    inner: HeaderValue::from(num),\n                    phantom: PhantomData,\n                }\n            }\n        }\n\n        #[test]\n        fn $name() {\n            let n: $t = 55;\n            let val = AsciiMetadataValue::from(n);\n            assert_eq!(val, &n.to_string());\n\n            let n = $t::MAX;\n            let val = AsciiMetadataValue::from(n);\n            assert_eq!(val, &n.to_string());\n        }\n    )*};\n}\n\nfrom_integers! {\n    // integer type => maximum decimal length\n\n    // u8 purposely left off... AsciiMetadataValue::from(b'3') could be confusing\n    from_u16: u16 => 5,\n    from_i16: i16 => 6,\n    from_u32: u32 => 10,\n    from_i32: i32 => 11,\n    from_u64: u64 => 20,\n    from_i64: i64 => 20\n}\n\n#[cfg(target_pointer_width = \"16\")]\nfrom_integers! {\n    from_usize: usize => 5,\n    from_isize: isize => 6\n}\n\n#[cfg(target_pointer_width = \"32\")]\nfrom_integers! {\n    from_usize: usize => 10,\n    from_isize: isize => 11\n}\n\n#[cfg(target_pointer_width = \"64\")]\nfrom_integers! {\n    from_usize: usize => 20,\n    from_isize: isize => 20\n}\n\n#[cfg(test)]\nmod from_metadata_value_tests {\n    use super::*;\n    use crate::metadata::map::MetadataMap;\n\n    #[test]\n    fn it_can_insert_metadata_key_as_metadata_value() {\n        let mut map = MetadataMap::new();\n        map.insert(\n            \"accept\",\n            MetadataKey::<Ascii>::from_bytes(b\"hello-world\")\n                .unwrap()\n                .into(),\n        );\n\n        assert_eq!(\n            map.get(\"accept\").unwrap(),\n            AsciiMetadataValue::try_from(b\"hello-world\").unwrap()\n        );\n    }\n}\n\nimpl FromStr for MetadataValue<Ascii> {\n    type Err = InvalidMetadataValue;\n\n    #[inline]\n    fn from_str(s: &str) -> Result<MetadataValue<Ascii>, Self::Err> {\n        HeaderValue::from_str(s)\n            .map(|value| MetadataValue {\n                inner: value,\n                phantom: PhantomData,\n            })\n            .map_err(|_| InvalidMetadataValue::new())\n    }\n}\n\nimpl<VE: ValueEncoding> From<MetadataValue<VE>> for Bytes {\n    #[inline]\n    fn from(value: MetadataValue<VE>) -> Bytes {\n        Bytes::copy_from_slice(value.inner.as_bytes())\n    }\n}\n\nimpl<'a, VE: ValueEncoding> From<&'a MetadataValue<VE>> for MetadataValue<VE> {\n    #[inline]\n    fn from(t: &'a MetadataValue<VE>) -> Self {\n        t.clone()\n    }\n}\n\n// ===== ToStrError =====\n\nimpl ToStrError {\n    pub(crate) fn new() -> Self {\n        ToStrError { _priv: () }\n    }\n}\n\nimpl fmt::Display for ToStrError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"failed to convert metadata to a str\")\n    }\n}\n\nimpl Error for ToStrError {}\n\nimpl Hash for MetadataValue<Ascii> {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.inner.hash(state)\n    }\n}\n\nimpl Hash for MetadataValue<Binary> {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        match self.to_bytes() {\n            Ok(b) => b.hash(state),\n            Err(e) => e.hash(state),\n        }\n    }\n}\n\n// ===== PartialEq / PartialOrd =====\n\nimpl<VE: ValueEncoding> PartialEq for MetadataValue<VE> {\n    #[inline]\n    fn eq(&self, other: &MetadataValue<VE>) -> bool {\n        // Note: Different binary strings that after base64 decoding\n        // will count as the same value for Binary values. Also,\n        // different invalid base64 values count as equal for Binary\n        // values.\n        VE::values_equal(&self.inner, &other.inner)\n    }\n}\n\nimpl<VE: ValueEncoding> Eq for MetadataValue<VE> {}\n\nimpl<VE: ValueEncoding> PartialOrd for MetadataValue<VE> {\n    #[inline]\n    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl<VE: ValueEncoding> Ord for MetadataValue<VE> {\n    #[inline]\n    fn cmp(&self, other: &Self) -> cmp::Ordering {\n        self.inner.cmp(&other.inner)\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<str> for MetadataValue<VE> {\n    #[inline]\n    fn eq(&self, other: &str) -> bool {\n        VE::equals(&self.inner, other.as_bytes())\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<[u8]> for MetadataValue<VE> {\n    #[inline]\n    fn eq(&self, other: &[u8]) -> bool {\n        VE::equals(&self.inner, other)\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<str> for MetadataValue<VE> {\n    #[inline]\n    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {\n        self.inner.partial_cmp(other.as_bytes())\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<[u8]> for MetadataValue<VE> {\n    #[inline]\n    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {\n        self.inner.partial_cmp(other)\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for str {\n    #[inline]\n    fn eq(&self, other: &MetadataValue<VE>) -> bool {\n        *other == *self\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for [u8] {\n    #[inline]\n    fn eq(&self, other: &MetadataValue<VE>) -> bool {\n        *other == *self\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for str {\n    #[inline]\n    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {\n        self.as_bytes().partial_cmp(other.inner.as_bytes())\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for [u8] {\n    #[inline]\n    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {\n        self.partial_cmp(other.inner.as_bytes())\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<String> for MetadataValue<VE> {\n    #[inline]\n    fn eq(&self, other: &String) -> bool {\n        *self == other[..]\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<String> for MetadataValue<VE> {\n    #[inline]\n    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {\n        self.inner.partial_cmp(other.as_bytes())\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for String {\n    #[inline]\n    fn eq(&self, other: &MetadataValue<VE>) -> bool {\n        *other == *self\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for String {\n    #[inline]\n    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {\n        self.as_bytes().partial_cmp(other.inner.as_bytes())\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for &MetadataValue<VE> {\n    #[inline]\n    fn eq(&self, other: &MetadataValue<VE>) -> bool {\n        **self == *other\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for &MetadataValue<VE> {\n    #[inline]\n    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {\n        (**self).partial_cmp(other)\n    }\n}\n\nimpl<'a, VE: ValueEncoding, T: ?Sized> PartialEq<&'a T> for MetadataValue<VE>\nwhere\n    MetadataValue<VE>: PartialEq<T>,\n{\n    #[inline]\n    fn eq(&self, other: &&'a T) -> bool {\n        *self == **other\n    }\n}\n\nimpl<'a, VE: ValueEncoding, T: ?Sized> PartialOrd<&'a T> for MetadataValue<VE>\nwhere\n    MetadataValue<VE>: PartialOrd<T>,\n{\n    #[inline]\n    fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {\n        self.partial_cmp(*other)\n    }\n}\n\nimpl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for &str {\n    #[inline]\n    fn eq(&self, other: &MetadataValue<VE>) -> bool {\n        *other == *self\n    }\n}\n\nimpl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for &str {\n    #[inline]\n    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {\n        self.as_bytes().partial_cmp(other.inner.as_bytes())\n    }\n}\n\n#[test]\nfn test_debug() {\n    let cases = &[\n        (\"hello\", \"\\\"hello\\\"\"),\n        (\"hello \\\"world\\\"\", \"\\\"hello \\\\\\\"world\\\\\\\"\\\"\"),\n        (\"\\u{7FFF}hello\", \"\\\"\\\\xe7\\\\xbf\\\\xbfhello\\\"\"),\n    ];\n\n    for &(value, expected) in cases {\n        let val = AsciiMetadataValue::try_from(value.as_bytes()).unwrap();\n        let actual = format!(\"{val:?}\");\n        assert_eq!(expected, actual);\n    }\n\n    let mut sensitive = AsciiMetadataValue::from_static(\"password\");\n    sensitive.set_sensitive(true);\n    assert_eq!(\"Sensitive\", format!(\"{sensitive:?}\"));\n}\n\n#[test]\nfn test_is_empty() {\n    fn from_str<VE: ValueEncoding>(s: &str) -> MetadataValue<VE> {\n        MetadataValue::<VE>::unchecked_from_header_value(s.parse().unwrap())\n    }\n\n    assert!(from_str::<Ascii>(\"\").is_empty());\n    assert!(from_str::<Binary>(\"\").is_empty());\n    assert!(!from_str::<Ascii>(\"a\").is_empty());\n    assert!(!from_str::<Binary>(\"a\").is_empty());\n    assert!(!from_str::<Ascii>(\"=\").is_empty());\n    assert!(from_str::<Binary>(\"=\").is_empty());\n    assert!(!from_str::<Ascii>(\"===\").is_empty());\n    assert!(from_str::<Binary>(\"===\").is_empty());\n    assert!(!from_str::<Ascii>(\"=====\").is_empty());\n    assert!(from_str::<Binary>(\"=====\").is_empty());\n}\n\n#[test]\nfn test_from_shared_base64_encodes() {\n    let value = BinaryMetadataValue::try_from(Bytes::from_static(b\"Hello\")).unwrap();\n    assert_eq!(value.as_encoded_bytes(), b\"SGVsbG8\");\n}\n\n#[test]\nfn test_value_eq_value() {\n    type Bmv = BinaryMetadataValue;\n    type Amv = AsciiMetadataValue;\n\n    assert_eq!(Amv::from_static(\"abc\"), Amv::from_static(\"abc\"));\n    assert_ne!(Amv::from_static(\"abc\"), Amv::from_static(\"ABC\"));\n\n    assert_eq!(Bmv::from_bytes(b\"abc\"), Bmv::from_bytes(b\"abc\"));\n    assert_ne!(Bmv::from_bytes(b\"abc\"), Bmv::from_bytes(b\"ABC\"));\n\n    // Padding is ignored.\n    assert_eq!(\n        Bmv::from_static(\"SGVsbG8hIQ==\"),\n        Bmv::from_static(\"SGVsbG8hIQ\")\n    );\n    // Invalid values are all just invalid from this point of view.\n    unsafe {\n        assert_eq!(\n            Bmv::from_shared_unchecked(Bytes::from_static(b\"..{}\")),\n            Bmv::from_shared_unchecked(Bytes::from_static(b\"{}..\"))\n        );\n    }\n}\n\n#[test]\nfn test_value_eq_str() {\n    type Bmv = BinaryMetadataValue;\n    type Amv = AsciiMetadataValue;\n\n    assert_eq!(Amv::from_static(\"abc\"), \"abc\");\n    assert_ne!(Amv::from_static(\"abc\"), \"ABC\");\n    assert_eq!(\"abc\", Amv::from_static(\"abc\"));\n    assert_ne!(\"ABC\", Amv::from_static(\"abc\"));\n\n    assert_eq!(Bmv::from_bytes(b\"abc\"), \"abc\");\n    assert_ne!(Bmv::from_bytes(b\"abc\"), \"ABC\");\n    assert_eq!(\"abc\", Bmv::from_bytes(b\"abc\"));\n    assert_ne!(\"ABC\", Bmv::from_bytes(b\"abc\"));\n\n    // Padding is ignored.\n    assert_eq!(Bmv::from_static(\"SGVsbG8hIQ==\"), \"Hello!!\");\n    assert_eq!(\"Hello!!\", Bmv::from_static(\"SGVsbG8hIQ==\"));\n}\n\n#[test]\nfn test_value_eq_bytes() {\n    type Bmv = BinaryMetadataValue;\n    type Amv = AsciiMetadataValue;\n\n    assert_eq!(Amv::from_static(\"abc\"), \"abc\".as_bytes());\n    assert_ne!(Amv::from_static(\"abc\"), \"ABC\".as_bytes());\n    assert_eq!(*\"abc\".as_bytes(), Amv::from_static(\"abc\"));\n    assert_ne!(*\"ABC\".as_bytes(), Amv::from_static(\"abc\"));\n\n    assert_eq!(*\"abc\".as_bytes(), Bmv::from_bytes(b\"abc\"));\n    assert_ne!(*\"ABC\".as_bytes(), Bmv::from_bytes(b\"abc\"));\n\n    // Padding is ignored.\n    assert_eq!(Bmv::from_static(\"SGVsbG8hIQ==\"), \"Hello!!\".as_bytes());\n    assert_eq!(*\"Hello!!\".as_bytes(), Bmv::from_static(\"SGVsbG8hIQ==\"));\n}\n\n#[test]\nfn test_ascii_value_hash() {\n    use std::collections::hash_map::DefaultHasher;\n    type Amv = AsciiMetadataValue;\n\n    fn hash(value: Amv) -> u64 {\n        let mut hasher = DefaultHasher::new();\n        value.hash(&mut hasher);\n        hasher.finish()\n    }\n\n    let value1 = Amv::from_static(\"abc\");\n    let value2 = Amv::from_static(\"abc\");\n    assert_eq!(value1, value2);\n    assert_eq!(hash(value1), hash(value2));\n\n    let value1 = Amv::from_static(\"abc\");\n    let value2 = Amv::from_static(\"xyz\");\n\n    assert_ne!(value1, value2);\n    assert_ne!(hash(value1), hash(value2));\n}\n\n#[test]\nfn test_valid_binary_value_hash() {\n    use std::collections::hash_map::DefaultHasher;\n    type Bmv = BinaryMetadataValue;\n\n    fn hash(value: Bmv) -> u64 {\n        let mut hasher = DefaultHasher::new();\n        value.hash(&mut hasher);\n        hasher.finish()\n    }\n\n    let value1 = Bmv::from_bytes(b\"abc\");\n    let value2 = Bmv::from_bytes(b\"abc\");\n    assert_eq!(value1, value2);\n    assert_eq!(hash(value1), hash(value2));\n\n    let value1 = Bmv::from_bytes(b\"abc\");\n    let value2 = Bmv::from_bytes(b\"xyz\");\n    assert_ne!(value1, value2);\n    assert_ne!(hash(value1), hash(value2));\n}\n\n#[test]\nfn test_invalid_binary_value_hash() {\n    use std::collections::hash_map::DefaultHasher;\n    type Bmv = BinaryMetadataValue;\n\n    fn hash(value: Bmv) -> u64 {\n        let mut hasher = DefaultHasher::new();\n        value.hash(&mut hasher);\n        hasher.finish()\n    }\n\n    unsafe {\n        let value1 = Bmv::from_shared_unchecked(Bytes::from_static(b\"..{}\"));\n        let value2 = Bmv::from_shared_unchecked(Bytes::from_static(b\"{}..\"));\n        assert_eq!(value1, value2);\n        assert_eq!(hash(value1), hash(value2));\n    }\n\n    unsafe {\n        let valid = Bmv::from_bytes(b\"abc\");\n        let invalid = Bmv::from_shared_unchecked(Bytes::from_static(b\"{}..\"));\n        assert_ne!(valid, invalid);\n        assert_ne!(hash(valid), hash(invalid));\n    }\n}\n"
  },
  {
    "path": "tonic/src/request.rs",
    "content": "use crate::metadata::{MetadataMap, MetadataValue};\n#[cfg(feature = \"server\")]\nuse crate::transport::server::TcpConnectInfo;\n#[cfg(all(feature = \"server\", feature = \"_tls-any\"))]\nuse crate::transport::server::TlsConnectInfo;\nuse http::Extensions;\n#[cfg(feature = \"server\")]\nuse std::net::SocketAddr;\n#[cfg(all(feature = \"server\", feature = \"_tls-any\"))]\nuse std::sync::Arc;\nuse std::time::Duration;\n#[cfg(all(feature = \"server\", feature = \"_tls-any\"))]\nuse tokio_rustls::rustls::pki_types::CertificateDer;\nuse tokio_stream::Stream;\n\n/// A gRPC request and metadata from an RPC call.\n#[derive(Debug)]\npub struct Request<T> {\n    metadata: MetadataMap,\n    message: T,\n    extensions: Extensions,\n}\n\n/// Trait implemented by RPC request types.\n///\n/// Types implementing this trait can be used as arguments to client RPC\n/// methods without explicitly wrapping them into `tonic::Request`s. The purpose\n/// is to make client calls slightly more convenient to write.\n///\n/// Tonic's code generation and blanket implementations handle this for you,\n/// so it is not necessary to implement this trait directly.\n///\n/// # Example\n///\n/// Given the following gRPC method definition:\n/// ```proto\n/// rpc GetFeature(Point) returns (Feature) {}\n/// ```\n///\n/// we can call `get_feature` in two equivalent ways:\n/// ```rust\n/// # pub struct Point {}\n/// # pub struct Client {}\n/// # impl Client {\n/// #   fn get_feature(&self, r: impl tonic::IntoRequest<Point>) {}\n/// # }\n/// # let client = Client {};\n/// use tonic::Request;\n///\n/// client.get_feature(Point {});\n/// client.get_feature(Request::new(Point {}));\n/// ```\npub trait IntoRequest<T>: sealed::Sealed {\n    /// Wrap the input message `T` in a `tonic::Request`\n    fn into_request(self) -> Request<T>;\n}\n\n/// Trait implemented by RPC streaming request types.\n///\n/// Types implementing this trait can be used as arguments to client streaming\n/// RPC methods without explicitly wrapping them into `tonic::Request`s. The\n/// purpose is to make client calls slightly more convenient to write.\n///\n/// Tonic's code generation and blanket implementations handle this for you,\n/// so it is not necessary to implement this trait directly.\n///\n/// # Example\n///\n/// Given the following gRPC service method definition:\n/// ```proto\n/// rpc RecordRoute(stream Point) returns (RouteSummary) {}\n/// ```\n/// we can call `record_route` in two equivalent ways:\n///\n/// ```rust\n/// # #[derive(Clone)]\n/// # pub struct Point {};\n/// # pub struct Client {};\n/// # impl Client {\n/// #   fn record_route(&self, r: impl tonic::IntoStreamingRequest<Message = Point>) {}\n/// # }\n/// # let client = Client {};\n/// use tonic::Request;\n///\n/// let messages = vec![Point {}, Point {}];\n///\n/// client.record_route(Request::new(tokio_stream::iter(messages.clone())));\n/// client.record_route(tokio_stream::iter(messages));\n/// ```\npub trait IntoStreamingRequest: sealed::Sealed {\n    /// The RPC request stream type\n    type Stream: Stream<Item = Self::Message> + Send + 'static;\n\n    /// The RPC request type\n    type Message;\n\n    /// Wrap the stream of messages in a `tonic::Request`\n    fn into_streaming_request(self) -> Request<Self::Stream>;\n}\n\nimpl<T> Request<T> {\n    /// Create a new gRPC request.\n    ///\n    /// ```rust\n    /// # use tonic::Request;\n    /// # pub struct HelloRequest {\n    /// #   pub name: String,\n    /// # }\n    /// Request::new(HelloRequest {\n    ///    name: \"Bob\".into(),\n    /// });\n    /// ```\n    pub fn new(message: T) -> Self {\n        Request {\n            metadata: MetadataMap::new(),\n            message,\n            extensions: Extensions::new(),\n        }\n    }\n\n    /// Get a reference to the message\n    pub fn get_ref(&self) -> &T {\n        &self.message\n    }\n\n    /// Get a mutable reference to the message\n    pub fn get_mut(&mut self) -> &mut T {\n        &mut self.message\n    }\n\n    /// Get a reference to the custom request metadata.\n    pub fn metadata(&self) -> &MetadataMap {\n        &self.metadata\n    }\n\n    /// Get a mutable reference to the request metadata.\n    pub fn metadata_mut(&mut self) -> &mut MetadataMap {\n        &mut self.metadata\n    }\n\n    /// Consumes `self`, returning the message\n    pub fn into_inner(self) -> T {\n        self.message\n    }\n\n    /// Consumes `self` returning the parts of the request.\n    pub fn into_parts(self) -> (MetadataMap, Extensions, T) {\n        (self.metadata, self.extensions, self.message)\n    }\n\n    /// Create a new gRPC request from metadata, extensions and message.\n    pub fn from_parts(metadata: MetadataMap, extensions: Extensions, message: T) -> Self {\n        Self {\n            metadata,\n            extensions,\n            message,\n        }\n    }\n\n    pub(crate) fn from_http_parts(parts: http::request::Parts, message: T) -> Self {\n        Request {\n            metadata: MetadataMap::from_headers(parts.headers),\n            message,\n            extensions: parts.extensions,\n        }\n    }\n\n    /// Convert an HTTP request to a gRPC request\n    pub fn from_http(http: http::Request<T>) -> Self {\n        let (parts, message) = http.into_parts();\n        Request::from_http_parts(parts, message)\n    }\n\n    pub(crate) fn into_http(\n        self,\n        uri: http::Uri,\n        method: http::Method,\n        version: http::Version,\n        sanitize_headers: SanitizeHeaders,\n    ) -> http::Request<T> {\n        let mut request = http::Request::new(self.message);\n\n        *request.version_mut() = version;\n        *request.method_mut() = method;\n        *request.uri_mut() = uri;\n        *request.headers_mut() = match sanitize_headers {\n            SanitizeHeaders::Yes => self.metadata.into_sanitized_headers(),\n            SanitizeHeaders::No => self.metadata.into_headers(),\n        };\n        *request.extensions_mut() = self.extensions;\n\n        request\n    }\n\n    #[doc(hidden)]\n    pub fn map<F, U>(self, f: F) -> Request<U>\n    where\n        F: FnOnce(T) -> U,\n    {\n        let message = f(self.message);\n\n        Request {\n            metadata: self.metadata,\n            message,\n            extensions: self.extensions,\n        }\n    }\n\n    /// Get the local address of this connection.\n    ///\n    /// This will return `None` if the `IO` type used\n    /// does not implement `Connected` or when using a unix domain socket.\n    /// This currently only works on the server side.\n    #[cfg(feature = \"server\")]\n    pub fn local_addr(&self) -> Option<SocketAddr> {\n        let addr = self\n            .extensions()\n            .get::<TcpConnectInfo>()\n            .and_then(|i| i.local_addr());\n\n        #[cfg(feature = \"_tls-any\")]\n        let addr = addr.or_else(|| {\n            self.extensions()\n                .get::<TlsConnectInfo<TcpConnectInfo>>()\n                .and_then(|i| i.get_ref().local_addr())\n        });\n\n        addr\n    }\n\n    /// Get the remote address of this connection.\n    ///\n    /// This will return `None` if the `IO` type used\n    /// does not implement `Connected` or when using a unix domain socket.\n    /// This currently only works on the server side.\n    #[cfg(feature = \"server\")]\n    pub fn remote_addr(&self) -> Option<SocketAddr> {\n        let addr = self\n            .extensions()\n            .get::<TcpConnectInfo>()\n            .and_then(|i| i.remote_addr());\n\n        #[cfg(feature = \"_tls-any\")]\n        let addr = addr.or_else(|| {\n            self.extensions()\n                .get::<TlsConnectInfo<TcpConnectInfo>>()\n                .and_then(|i| i.get_ref().remote_addr())\n        });\n\n        addr\n    }\n\n    /// Get the peer certificates of the connected client.\n    ///\n    /// This is used to fetch the certificates from the TLS session\n    /// and is mostly used for mTLS. This currently only returns\n    /// `Some` on the server side of the `transport` server with\n    /// TLS enabled connections.\n    #[cfg(all(feature = \"server\", feature = \"_tls-any\"))]\n    pub fn peer_certs(&self) -> Option<Arc<Vec<CertificateDer<'static>>>> {\n        self.extensions()\n            .get::<TlsConnectInfo<TcpConnectInfo>>()\n            .and_then(|i| i.peer_certs())\n    }\n\n    /// Set the max duration the request is allowed to take.\n    ///\n    /// Requires the server to support the `grpc-timeout` metadata, which Tonic does.\n    ///\n    /// The duration will be formatted according to [the spec] and use the most precise unit\n    /// possible.\n    ///\n    /// Example:\n    ///\n    /// ```rust\n    /// use std::time::Duration;\n    /// use tonic::Request;\n    ///\n    /// let mut request = Request::new(());\n    ///\n    /// request.set_timeout(Duration::from_secs(30));\n    ///\n    /// let value = request.metadata().get(\"grpc-timeout\").unwrap();\n    ///\n    /// assert_eq!(\n    ///     value,\n    ///     // equivalent to 30 seconds\n    ///     \"30000000u\"\n    /// );\n    /// ```\n    ///\n    /// [the spec]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md\n    pub fn set_timeout(&mut self, deadline: Duration) {\n        let value: MetadataValue<_> = duration_to_grpc_timeout(deadline).parse().unwrap();\n        self.metadata_mut()\n            .insert(crate::metadata::GRPC_TIMEOUT_HEADER, value);\n    }\n\n    /// Returns a reference to the associated extensions.\n    pub fn extensions(&self) -> &Extensions {\n        &self.extensions\n    }\n\n    /// Returns a mutable reference to the associated extensions.\n    ///\n    /// # Example\n    ///\n    /// Extensions can be set in interceptors:\n    ///\n    /// ```no_run\n    /// use tonic::{Request, Status};\n    ///\n    /// #[derive(Clone)] // Extensions must be Clone\n    /// struct MyExtension {\n    ///     some_piece_of_data: String,\n    /// }\n    ///\n    /// fn intercept(mut request: Request<()>) -> Result<Request<()>, Status> {\n    ///     request.extensions_mut().insert(MyExtension {\n    ///         some_piece_of_data: \"foo\".to_string(),\n    ///     });\n    ///\n    ///     Ok(request)\n    /// }\n    /// ```\n    ///\n    /// And picked up by RPCs:\n    ///\n    /// ```no_run\n    /// use tonic::{async_trait, Status, Request, Response};\n    /// #\n    /// # struct Output {}\n    /// # struct Input;\n    /// # struct MyService;\n    /// # struct MyExtension;\n    /// # #[async_trait]\n    /// # trait TestService {\n    /// #     async fn handler(&self, req: Request<Input>) -> Result<Response<Output>, Status>;\n    /// # }\n    ///\n    /// #[async_trait]\n    /// impl TestService for MyService {\n    ///     async fn handler(&self, req: Request<Input>) -> Result<Response<Output>, Status> {\n    ///         let value: &MyExtension = req.extensions().get::<MyExtension>().unwrap();\n    ///\n    ///         Ok(Response::new(Output {}))\n    ///     }\n    /// }\n    /// ```\n    pub fn extensions_mut(&mut self) -> &mut Extensions {\n        &mut self.extensions\n    }\n}\n\nimpl<T> IntoRequest<T> for T {\n    fn into_request(self) -> Request<Self> {\n        Request::new(self)\n    }\n}\n\nimpl<T> IntoRequest<T> for Request<T> {\n    fn into_request(self) -> Request<T> {\n        self\n    }\n}\n\nimpl<T> IntoStreamingRequest for T\nwhere\n    T: Stream + Send + 'static,\n{\n    type Stream = T;\n    type Message = T::Item;\n\n    fn into_streaming_request(self) -> Request<Self> {\n        Request::new(self)\n    }\n}\n\nimpl<T> IntoStreamingRequest for Request<T>\nwhere\n    T: Stream + Send + 'static,\n{\n    type Stream = T;\n    type Message = T::Item;\n\n    fn into_streaming_request(self) -> Self {\n        self\n    }\n}\n\nimpl<T> sealed::Sealed for T {}\n\nmod sealed {\n    pub trait Sealed {}\n}\n\nfn duration_to_grpc_timeout(duration: Duration) -> String {\n    fn try_format<T: Into<u128>>(\n        duration: Duration,\n        unit: char,\n        convert: impl FnOnce(Duration) -> T,\n    ) -> Option<String> {\n        // The gRPC spec specifies that the timeout most be at most 8 digits. So this is the largest a\n        // value can be before we need to use a bigger unit.\n        let max_size: u128 = 99_999_999; // exactly 8 digits\n\n        let value = convert(duration).into();\n        if value > max_size {\n            None\n        } else {\n            Some(format!(\"{value}{unit}\"))\n        }\n    }\n\n    // pick the most precise unit that is less than or equal to 8 digits as per the gRPC spec\n    try_format(duration, 'n', |d| d.as_nanos())\n        .or_else(|| try_format(duration, 'u', |d| d.as_micros()))\n        .or_else(|| try_format(duration, 'm', |d| d.as_millis()))\n        .or_else(|| try_format(duration, 'S', |d| d.as_secs()))\n        .or_else(|| try_format(duration, 'M', |d| d.as_secs() / 60))\n        .or_else(|| {\n            try_format(duration, 'H', |d| {\n                let minutes = d.as_secs() / 60;\n                minutes / 60\n            })\n        })\n        // duration has to be more than 11_415 years for this to happen\n        .expect(\"duration is unrealistically large\")\n}\n\n/// When converting a `tonic::Request` into a `http::Request` should reserved\n/// headers be removed?\npub(crate) enum SanitizeHeaders {\n    Yes,\n    No,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::metadata::{MetadataKey, MetadataValue};\n\n    use http::Uri;\n\n    #[test]\n    fn reserved_headers_are_excluded() {\n        let mut r = Request::new(1);\n\n        for header in &MetadataMap::GRPC_RESERVED_HEADERS {\n            r.metadata_mut().insert(\n                MetadataKey::unchecked_from_header_name(header.clone()),\n                MetadataValue::from_static(\"invalid\"),\n            );\n        }\n\n        let http_request = r.into_http(\n            Uri::default(),\n            http::Method::POST,\n            http::Version::HTTP_2,\n            SanitizeHeaders::Yes,\n        );\n        assert!(http_request.headers().is_empty());\n    }\n\n    #[test]\n    fn preserves_user_agent() {\n        let mut r = Request::new(1);\n\n        r.metadata_mut().insert(\n            MetadataKey::from_static(\"user-agent\"),\n            MetadataValue::from_static(\"Custom/1.2.3\"),\n        );\n\n        let http_request = r.into_http(\n            Uri::default(),\n            http::Method::POST,\n            http::Version::HTTP_2,\n            SanitizeHeaders::Yes,\n        );\n        let user_agent = http_request.headers().get(\"user-agent\").unwrap();\n        assert_eq!(user_agent, \"Custom/1.2.3\");\n    }\n\n    #[test]\n    fn duration_to_grpc_timeout_less_than_second() {\n        let timeout = Duration::from_millis(500);\n        let value = duration_to_grpc_timeout(timeout);\n        assert_eq!(value, format!(\"{}u\", timeout.as_micros()));\n    }\n\n    #[test]\n    fn duration_to_grpc_timeout_more_than_second() {\n        let timeout = Duration::from_secs(30);\n        let value = duration_to_grpc_timeout(timeout);\n        assert_eq!(value, format!(\"{}u\", timeout.as_micros()));\n    }\n\n    #[test]\n    fn duration_to_grpc_timeout_a_very_long_time() {\n        let one_hour = Duration::from_secs(60 * 60);\n        let value = duration_to_grpc_timeout(one_hour);\n        assert_eq!(value, format!(\"{}m\", one_hour.as_millis()));\n    }\n}\n"
  },
  {
    "path": "tonic/src/response.rs",
    "content": "use http::Extensions;\n\nuse crate::metadata::MetadataMap;\n\n/// A gRPC response and metadata from an RPC call.\n#[derive(Debug)]\npub struct Response<T> {\n    metadata: MetadataMap,\n    message: T,\n    extensions: Extensions,\n}\n\nimpl<T> Response<T> {\n    /// Create a new gRPC response.\n    ///\n    /// ```rust\n    /// # use tonic::Response;\n    /// # pub struct HelloReply {\n    /// #   pub message: String,\n    /// # }\n    /// # let name = \"\";\n    /// Response::new(HelloReply {\n    ///     message: format!(\"Hello, {}!\", name).into(),\n    /// });\n    /// ```\n    pub fn new(message: T) -> Self {\n        Response {\n            metadata: MetadataMap::new(),\n            message,\n            extensions: Extensions::new(),\n        }\n    }\n\n    /// Get a immutable reference to `T`.\n    pub fn get_ref(&self) -> &T {\n        &self.message\n    }\n\n    /// Get a mutable reference to the message\n    pub fn get_mut(&mut self) -> &mut T {\n        &mut self.message\n    }\n\n    /// Get a reference to the custom response metadata.\n    pub fn metadata(&self) -> &MetadataMap {\n        &self.metadata\n    }\n\n    /// Get a mutable reference to the response metadata.\n    pub fn metadata_mut(&mut self) -> &mut MetadataMap {\n        &mut self.metadata\n    }\n\n    /// Consumes `self`, returning the message\n    pub fn into_inner(self) -> T {\n        self.message\n    }\n\n    /// Consumes `self` returning the parts of the response.\n    pub fn into_parts(self) -> (MetadataMap, T, Extensions) {\n        (self.metadata, self.message, self.extensions)\n    }\n\n    /// Create a new gRPC response from metadata, message and extensions.\n    pub fn from_parts(metadata: MetadataMap, message: T, extensions: Extensions) -> Self {\n        Self {\n            metadata,\n            message,\n            extensions,\n        }\n    }\n\n    pub(crate) fn from_http(res: http::Response<T>) -> Self {\n        let (head, message) = res.into_parts();\n        Response {\n            metadata: MetadataMap::from_headers(head.headers),\n            message,\n            extensions: head.extensions,\n        }\n    }\n\n    pub(crate) fn into_http(self) -> http::Response<T> {\n        let mut res = http::Response::new(self.message);\n\n        *res.version_mut() = http::Version::HTTP_2;\n        *res.headers_mut() = self.metadata.into_sanitized_headers();\n        *res.extensions_mut() = self.extensions;\n\n        res\n    }\n\n    #[doc(hidden)]\n    pub fn map<F, U>(self, f: F) -> Response<U>\n    where\n        F: FnOnce(T) -> U,\n    {\n        let message = f(self.message);\n        Response {\n            metadata: self.metadata,\n            message,\n            extensions: self.extensions,\n        }\n    }\n\n    /// Returns a reference to the associated extensions.\n    pub fn extensions(&self) -> &Extensions {\n        &self.extensions\n    }\n\n    /// Returns a mutable reference to the associated extensions.\n    pub fn extensions_mut(&mut self) -> &mut Extensions {\n        &mut self.extensions\n    }\n\n    /// Disable compression of the response body.\n    ///\n    /// This disables compression of the body of this response, even if compression is enabled on\n    /// the server.\n    ///\n    /// **Note**: This only has effect on responses to unary requests and responses to client to\n    /// server streams. Response streams (server to client stream and bidirectional streams) will\n    /// still be compressed according to the configuration of the server.\n    #[cfg(any(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n    pub fn disable_compression(&mut self) {\n        self.extensions_mut()\n            .insert(crate::codec::compression::SingleMessageCompressionOverride::Disable);\n    }\n}\n\nimpl<T> From<T> for Response<T> {\n    fn from(inner: T) -> Self {\n        Response::new(inner)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::metadata::{MetadataKey, MetadataValue};\n\n    #[test]\n    fn reserved_headers_are_excluded() {\n        let mut r = Response::new(1);\n\n        for header in &MetadataMap::GRPC_RESERVED_HEADERS {\n            r.metadata_mut().insert(\n                MetadataKey::unchecked_from_header_name(header.clone()),\n                MetadataValue::from_static(\"invalid\"),\n            );\n        }\n\n        let http_response = r.into_http();\n        assert!(http_response.headers().is_empty());\n    }\n}\n"
  },
  {
    "path": "tonic/src/server/grpc.rs",
    "content": "use crate::codec::EncodeBody;\nuse crate::codec::compression::{\n    CompressionEncoding, EnabledCompressionEncodings, SingleMessageCompressionOverride,\n};\nuse crate::metadata::GRPC_CONTENT_TYPE;\nuse crate::{\n    Request, Status,\n    body::Body,\n    codec::{Codec, Streaming},\n    server::{ClientStreamingService, ServerStreamingService, StreamingService, UnaryService},\n};\nuse http_body::Body as HttpBody;\nuse std::{fmt, pin::pin};\nuse tokio_stream::{Stream, StreamExt};\n\nmacro_rules! t {\n    ($result:expr) => {\n        match $result {\n            Ok(value) => value,\n            Err(status) => return status.into_http(),\n        }\n    };\n}\n\n/// A gRPC Server handler.\n///\n/// This will wrap some inner [`Codec`] and provide utilities to handle\n/// inbound unary, client side streaming, server side streaming, and\n/// bi-directional streaming.\n///\n/// Each request handler method accepts some service that implements the\n/// corresponding service trait and a http request that contains some body that\n/// implements some [`Body`].\npub struct Grpc<T> {\n    codec: T,\n    /// Which compression encodings does the server accept for requests?\n    accept_compression_encodings: EnabledCompressionEncodings,\n    /// Which compression encodings might the server use for responses.\n    send_compression_encodings: EnabledCompressionEncodings,\n    /// Limits the maximum size of a decoded message.\n    max_decoding_message_size: Option<usize>,\n    /// Limits the maximum size of an encoded message.\n    max_encoding_message_size: Option<usize>,\n}\n\nimpl<T> Grpc<T>\nwhere\n    T: Codec,\n{\n    /// Creates a new gRPC server with the provided [`Codec`].\n    pub fn new(codec: T) -> Self {\n        Self {\n            codec,\n            accept_compression_encodings: EnabledCompressionEncodings::default(),\n            send_compression_encodings: EnabledCompressionEncodings::default(),\n            max_decoding_message_size: None,\n            max_encoding_message_size: None,\n        }\n    }\n\n    /// Enable accepting compressed requests.\n    ///\n    /// If a request with an unsupported encoding is received the server will respond with\n    /// [`Code::UnUnimplemented`](crate::Code).\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a server generated by tonic-build:\n    ///\n    /// ```rust\n    /// # enum CompressionEncoding { Gzip }\n    /// # struct Svc;\n    /// # struct ExampleServer<T>(T);\n    /// # impl<T> ExampleServer<T> {\n    /// #     fn new(svc: T) -> Self { Self(svc) }\n    /// #     fn accept_compressed(self, _: CompressionEncoding) -> Self { self }\n    /// # }\n    /// # #[tonic::async_trait]\n    /// # trait Example {}\n    ///\n    /// #[tonic::async_trait]\n    /// impl Example for Svc {\n    ///     // ...\n    /// }\n    ///\n    /// let service = ExampleServer::new(Svc).accept_compressed(CompressionEncoding::Gzip);\n    /// ```\n    pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n        self.accept_compression_encodings.enable(encoding);\n        self\n    }\n\n    /// Enable sending compressed responses.\n    ///\n    /// Requires the client to also support receiving compressed responses.\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a server generated by tonic-build:\n    ///\n    /// ```rust\n    /// # enum CompressionEncoding { Gzip }\n    /// # struct Svc;\n    /// # struct ExampleServer<T>(T);\n    /// # impl<T> ExampleServer<T> {\n    /// #     fn new(svc: T) -> Self { Self(svc) }\n    /// #     fn send_compressed(self, _: CompressionEncoding) -> Self { self }\n    /// # }\n    /// # #[tonic::async_trait]\n    /// # trait Example {}\n    ///\n    /// #[tonic::async_trait]\n    /// impl Example for Svc {\n    ///     // ...\n    /// }\n    ///\n    /// let service = ExampleServer::new(Svc).send_compressed(CompressionEncoding::Gzip);\n    /// ```\n    pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n        self.send_compression_encodings.enable(encoding);\n        self\n    }\n\n    /// Limits the maximum size of a decoded message.\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a server generated by tonic-build:\n    ///\n    /// ```rust\n    /// # struct Svc;\n    /// # struct ExampleServer<T>(T);\n    /// # impl<T> ExampleServer<T> {\n    /// #     fn new(svc: T) -> Self { Self(svc) }\n    /// #     fn max_decoding_message_size(self, _: usize) -> Self { self }\n    /// # }\n    /// # #[tonic::async_trait]\n    /// # trait Example {}\n    ///\n    /// #[tonic::async_trait]\n    /// impl Example for Svc {\n    ///     // ...\n    /// }\n    ///\n    /// // Set the limit to 2MB, Defaults to 4MB.\n    /// let limit = 2 * 1024 * 1024;\n    /// let service = ExampleServer::new(Svc).max_decoding_message_size(limit);\n    /// ```\n    pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n        self.max_decoding_message_size = Some(limit);\n        self\n    }\n\n    /// Limits the maximum size of a encoded message.\n    ///\n    /// # Example\n    ///\n    /// The most common way of using this is through a server generated by tonic-build:\n    ///\n    /// ```rust\n    /// # struct Svc;\n    /// # struct ExampleServer<T>(T);\n    /// # impl<T> ExampleServer<T> {\n    /// #     fn new(svc: T) -> Self { Self(svc) }\n    /// #     fn max_encoding_message_size(self, _: usize) -> Self { self }\n    /// # }\n    /// # #[tonic::async_trait]\n    /// # trait Example {}\n    ///\n    /// #[tonic::async_trait]\n    /// impl Example for Svc {\n    ///     // ...\n    /// }\n    ///\n    /// // Set the limit to 2MB, Defaults to 4MB.\n    /// let limit = 2 * 1024 * 1024;\n    /// let service = ExampleServer::new(Svc).max_encoding_message_size(limit);\n    /// ```\n    pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n        self.max_encoding_message_size = Some(limit);\n        self\n    }\n\n    #[doc(hidden)]\n    pub fn apply_compression_config(\n        mut self,\n        accept_encodings: EnabledCompressionEncodings,\n        send_encodings: EnabledCompressionEncodings,\n    ) -> Self {\n        for &encoding in CompressionEncoding::ENCODINGS {\n            if accept_encodings.is_enabled(encoding) {\n                self = self.accept_compressed(encoding);\n            }\n            if send_encodings.is_enabled(encoding) {\n                self = self.send_compressed(encoding);\n            }\n        }\n\n        self\n    }\n\n    #[doc(hidden)]\n    pub fn apply_max_message_size_config(\n        mut self,\n        max_decoding_message_size: Option<usize>,\n        max_encoding_message_size: Option<usize>,\n    ) -> Self {\n        if let Some(limit) = max_decoding_message_size {\n            self = self.max_decoding_message_size(limit);\n        }\n        if let Some(limit) = max_encoding_message_size {\n            self = self.max_encoding_message_size(limit);\n        }\n\n        self\n    }\n\n    /// Handle a single unary gRPC request.\n    pub async fn unary<S, B>(\n        &mut self,\n        mut service: S,\n        req: http::Request<B>,\n    ) -> http::Response<Body>\n    where\n        S: UnaryService<T::Decode, Response = T::Encode>,\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError> + Send,\n    {\n        let accept_encoding = CompressionEncoding::from_accept_encoding_header(\n            req.headers(),\n            self.send_compression_encodings,\n        );\n\n        let request = match self.map_request_unary(req).await {\n            Ok(r) => r,\n            Err(status) => {\n                return self.map_response::<tokio_stream::Once<Result<T::Encode, Status>>>(\n                    Err(status),\n                    accept_encoding,\n                    SingleMessageCompressionOverride::default(),\n                    self.max_encoding_message_size,\n                );\n            }\n        };\n\n        let response = service\n            .call(request)\n            .await\n            .map(|r| r.map(|m| tokio_stream::once(Ok(m))));\n\n        let compression_override = compression_override_from_response(&response);\n\n        self.map_response(\n            response,\n            accept_encoding,\n            compression_override,\n            self.max_encoding_message_size,\n        )\n    }\n\n    /// Handle a server side streaming request.\n    pub async fn server_streaming<S, B>(\n        &mut self,\n        mut service: S,\n        req: http::Request<B>,\n    ) -> http::Response<Body>\n    where\n        S: ServerStreamingService<T::Decode, Response = T::Encode>,\n        S::ResponseStream: Send + 'static,\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError> + Send,\n    {\n        let accept_encoding = CompressionEncoding::from_accept_encoding_header(\n            req.headers(),\n            self.send_compression_encodings,\n        );\n\n        let request = match self.map_request_unary(req).await {\n            Ok(r) => r,\n            Err(status) => {\n                return self.map_response::<S::ResponseStream>(\n                    Err(status),\n                    accept_encoding,\n                    SingleMessageCompressionOverride::default(),\n                    self.max_encoding_message_size,\n                );\n            }\n        };\n\n        let response = service.call(request).await;\n\n        self.map_response(\n            response,\n            accept_encoding,\n            // disabling compression of individual stream items must be done on\n            // the items themselves\n            SingleMessageCompressionOverride::default(),\n            self.max_encoding_message_size,\n        )\n    }\n\n    /// Handle a client side streaming gRPC request.\n    pub async fn client_streaming<S, B>(\n        &mut self,\n        mut service: S,\n        req: http::Request<B>,\n    ) -> http::Response<Body>\n    where\n        S: ClientStreamingService<T::Decode, Response = T::Encode>,\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError> + Send + 'static,\n    {\n        let accept_encoding = CompressionEncoding::from_accept_encoding_header(\n            req.headers(),\n            self.send_compression_encodings,\n        );\n\n        let request = t!(self.map_request_streaming(req));\n\n        let response = service\n            .call(request)\n            .await\n            .map(|r| r.map(|m| tokio_stream::once(Ok(m))));\n\n        let compression_override = compression_override_from_response(&response);\n\n        self.map_response(\n            response,\n            accept_encoding,\n            compression_override,\n            self.max_encoding_message_size,\n        )\n    }\n\n    /// Handle a bi-directional streaming gRPC request.\n    pub async fn streaming<S, B>(\n        &mut self,\n        mut service: S,\n        req: http::Request<B>,\n    ) -> http::Response<Body>\n    where\n        S: StreamingService<T::Decode, Response = T::Encode> + Send,\n        S::ResponseStream: Send + 'static,\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError> + Send,\n    {\n        let accept_encoding = CompressionEncoding::from_accept_encoding_header(\n            req.headers(),\n            self.send_compression_encodings,\n        );\n\n        let request = t!(self.map_request_streaming(req));\n\n        let response = service.call(request).await;\n\n        self.map_response(\n            response,\n            accept_encoding,\n            SingleMessageCompressionOverride::default(),\n            self.max_encoding_message_size,\n        )\n    }\n\n    async fn map_request_unary<B>(\n        &mut self,\n        request: http::Request<B>,\n    ) -> Result<Request<T::Decode>, Status>\n    where\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError> + Send,\n    {\n        let request_compression_encoding = self.request_encoding_if_supported(&request)?;\n\n        let (parts, body) = request.into_parts();\n\n        let mut stream = pin!(Streaming::new_request(\n            self.codec.decoder(),\n            body,\n            request_compression_encoding,\n            self.max_decoding_message_size,\n        ));\n\n        let message = stream\n            .try_next()\n            .await?\n            .ok_or_else(|| Status::internal(\"Missing request message.\"))?;\n\n        let mut req = Request::from_http_parts(parts, message);\n\n        if let Some(trailers) = stream.trailers().await? {\n            req.metadata_mut().merge(trailers);\n        }\n\n        Ok(req)\n    }\n\n    fn map_request_streaming<B>(\n        &mut self,\n        request: http::Request<B>,\n    ) -> Result<Request<Streaming<T::Decode>>, Status>\n    where\n        B: HttpBody + Send + 'static,\n        B::Error: Into<crate::BoxError> + Send,\n    {\n        let encoding = self.request_encoding_if_supported(&request)?;\n\n        let request = request.map(|body| {\n            Streaming::new_request(\n                self.codec.decoder(),\n                body,\n                encoding,\n                self.max_decoding_message_size,\n            )\n        });\n\n        Ok(Request::from_http(request))\n    }\n\n    fn map_response<B>(\n        &mut self,\n        response: Result<crate::Response<B>, Status>,\n        accept_encoding: Option<CompressionEncoding>,\n        compression_override: SingleMessageCompressionOverride,\n        max_message_size: Option<usize>,\n    ) -> http::Response<Body>\n    where\n        B: Stream<Item = Result<T::Encode, Status>> + Send + 'static,\n    {\n        let response = t!(response);\n\n        let (mut parts, body) = response.into_http().into_parts();\n\n        // Set the content type\n        parts\n            .headers\n            .insert(http::header::CONTENT_TYPE, GRPC_CONTENT_TYPE);\n\n        #[cfg(any(feature = \"gzip\", feature = \"deflate\", feature = \"zstd\"))]\n        if let Some(encoding) = accept_encoding {\n            // Set the content encoding\n            parts.headers.insert(\n                crate::codec::compression::ENCODING_HEADER,\n                encoding.into_header_value(),\n            );\n        }\n\n        let body = EncodeBody::new_server(\n            self.codec.encoder(),\n            body,\n            accept_encoding,\n            compression_override,\n            max_message_size,\n        );\n\n        http::Response::from_parts(parts, Body::new(body))\n    }\n\n    fn request_encoding_if_supported<B>(\n        &self,\n        request: &http::Request<B>,\n    ) -> Result<Option<CompressionEncoding>, Status> {\n        CompressionEncoding::from_encoding_header(\n            request.headers(),\n            self.accept_compression_encodings,\n        )\n    }\n}\n\nimpl<T: fmt::Debug> fmt::Debug for Grpc<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Grpc\")\n            .field(\"codec\", &self.codec)\n            .field(\n                \"accept_compression_encodings\",\n                &self.accept_compression_encodings,\n            )\n            .field(\n                \"send_compression_encodings\",\n                &self.send_compression_encodings,\n            )\n            .finish()\n    }\n}\n\nfn compression_override_from_response<B, E>(\n    res: &Result<crate::Response<B>, E>,\n) -> SingleMessageCompressionOverride {\n    res.as_ref()\n        .ok()\n        .and_then(|response| {\n            response\n                .extensions()\n                .get::<SingleMessageCompressionOverride>()\n                .copied()\n        })\n        .unwrap_or_default()\n}\n"
  },
  {
    "path": "tonic/src/server/mod.rs",
    "content": "//! Generic server implementation.\n//!\n//! This module contains the low level components to build a gRPC server. It\n//! provides a codec agnostic gRPC server handler.\n//!\n//! The items in this module are generally designed to be used by some codegen\n//! tool that will provide the user some custom way to implement the server that\n//! will implement the proper gRPC service. Thusly, they are a bit hard to use\n//! by hand.\n\nmod grpc;\nmod service;\n\npub use self::grpc::Grpc;\npub use self::service::{\n    ClientStreamingService, ServerStreamingService, StreamingService, UnaryService,\n};\n\n/// A trait to provide a static reference to the service's\n/// name. This is used for routing service's within the router.\npub trait NamedService {\n    /// The `Service-Name` as described [here].\n    ///\n    /// [here]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests\n    const NAME: &'static str;\n}\n"
  },
  {
    "path": "tonic/src/server/service.rs",
    "content": "use crate::{Request, Response, Status, Streaming};\nuse std::future::Future;\nuse tokio_stream::Stream;\nuse tower_service::Service;\n\n/// A specialization of tower_service::Service.\n///\n/// Existing tower_service::Service implementations with the correct form will\n/// automatically implement `UnaryService`.\npub trait UnaryService<R> {\n    /// Protobuf response message type\n    type Response;\n\n    /// Response future\n    type Future: Future<Output = Result<Response<Self::Response>, Status>>;\n\n    /// Call the service\n    fn call(&mut self, request: Request<R>) -> Self::Future;\n}\n\nimpl<T, M1, M2> UnaryService<M1> for T\nwhere\n    T: Service<Request<M1>, Response = Response<M2>, Error = crate::Status>,\n{\n    type Response = M2;\n    type Future = T::Future;\n\n    fn call(&mut self, request: Request<M1>) -> Self::Future {\n        Service::call(self, request)\n    }\n}\n\n/// A specialization of tower_service::Service.\n///\n/// Existing tower_service::Service implementations with the correct form will\n/// automatically implement `ServerStreamingService`.\npub trait ServerStreamingService<R> {\n    /// Protobuf response message type\n    type Response;\n\n    /// Stream of outbound response messages\n    type ResponseStream: Stream<Item = Result<Self::Response, Status>>;\n\n    /// Response future\n    type Future: Future<Output = Result<Response<Self::ResponseStream>, Status>>;\n\n    /// Call the service\n    fn call(&mut self, request: Request<R>) -> Self::Future;\n}\n\nimpl<T, S, M1, M2> ServerStreamingService<M1> for T\nwhere\n    T: Service<Request<M1>, Response = Response<S>, Error = crate::Status>,\n    S: Stream<Item = Result<M2, crate::Status>>,\n{\n    type Response = M2;\n    type ResponseStream = S;\n    type Future = T::Future;\n\n    fn call(&mut self, request: Request<M1>) -> Self::Future {\n        Service::call(self, request)\n    }\n}\n\n/// A specialization of tower_service::Service.\n///\n/// Existing tower_service::Service implementations with the correct form will\n/// automatically implement `ClientStreamingService`.\npub trait ClientStreamingService<R> {\n    /// Protobuf response message type\n    type Response;\n\n    /// Response future\n    type Future: Future<Output = Result<Response<Self::Response>, Status>>;\n\n    /// Call the service\n    fn call(&mut self, request: Request<Streaming<R>>) -> Self::Future;\n}\n\nimpl<T, M1, M2> ClientStreamingService<M1> for T\nwhere\n    T: Service<Request<Streaming<M1>>, Response = Response<M2>, Error = crate::Status>,\n{\n    type Response = M2;\n    type Future = T::Future;\n\n    fn call(&mut self, request: Request<Streaming<M1>>) -> Self::Future {\n        Service::call(self, request)\n    }\n}\n\n/// A specialization of tower_service::Service.\n///\n/// Existing tower_service::Service implementations with the correct form will\n/// automatically implement `StreamingService`.\npub trait StreamingService<R> {\n    /// Protobuf response message type\n    type Response;\n\n    /// Stream of outbound response messages\n    type ResponseStream: Stream<Item = Result<Self::Response, Status>>;\n\n    /// Response future\n    type Future: Future<Output = Result<Response<Self::ResponseStream>, Status>>;\n\n    /// Call the service\n    fn call(&mut self, request: Request<Streaming<R>>) -> Self::Future;\n}\n\nimpl<T, S, M1, M2> StreamingService<M1> for T\nwhere\n    T: Service<Request<Streaming<M1>>, Response = Response<S>, Error = crate::Status>,\n    S: Stream<Item = Result<M2, crate::Status>>,\n{\n    type Response = M2;\n    type ResponseStream = S;\n    type Future = T::Future;\n\n    fn call(&mut self, request: Request<Streaming<M1>>) -> Self::Future {\n        Service::call(self, request)\n    }\n}\n"
  },
  {
    "path": "tonic/src/service/interceptor.rs",
    "content": "//! gRPC interceptors which are a kind of middleware.\n//!\n//! See [`Interceptor`] for more details.\n\nuse crate::{Status, request::SanitizeHeaders};\nuse pin_project::pin_project;\nuse std::{\n    fmt,\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tower_layer::Layer;\nuse tower_service::Service;\n\n/// A gRPC interceptor.\n///\n/// gRPC interceptors are similar to middleware but have less flexibility. An interceptor allows\n/// you to do two main things, one is to add/remove/check items in the `MetadataMap` of each\n/// request. Two, cancel a request with a `Status`.\n///\n/// Any function that satisfies the bound `FnMut(Request<()>) -> Result<Request<()>, Status>` can be\n/// used as an `Interceptor`.\n///\n/// An interceptor can be used on both the server and client side through the `tonic-build` crate's\n/// generated structs.\n///\n/// See the [interceptor example][example] for more details.\n///\n/// If you need more powerful middleware, [tower] is the recommended approach. You can find\n/// examples of how to use tower with tonic [here][tower-example].\n///\n/// Additionally, interceptors is not the recommended way to add logging to your service. For that\n/// a [tower] middleware is more appropriate since it can also act on the response. For example\n/// tower-http's [`Trace`](https://docs.rs/tower-http/latest/tower_http/trace/index.html)\n/// middleware supports gRPC out of the box.\n///\n/// [tower]: https://crates.io/crates/tower\n/// [example]: https://github.com/hyperium/tonic/tree/master/examples/src/interceptor\n/// [tower-example]: https://github.com/hyperium/tonic/tree/master/examples/src/tower\npub trait Interceptor {\n    /// Intercept a request before it is sent, optionally cancelling it.\n    fn call(&mut self, request: crate::Request<()>) -> Result<crate::Request<()>, Status>;\n}\n\nimpl<F> Interceptor for F\nwhere\n    F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,\n{\n    fn call(&mut self, request: crate::Request<()>) -> Result<crate::Request<()>, Status> {\n        self(request)\n    }\n}\n\n/// A gRPC interceptor that can be used as a [`Layer`],\n///\n/// See [`Interceptor`] for more details.\n#[derive(Debug, Clone, Copy)]\npub struct InterceptorLayer<I> {\n    interceptor: I,\n}\n\nimpl<I> InterceptorLayer<I> {\n    /// Create a new interceptor layer.\n    ///\n    /// See [`Interceptor`] for more details.\n    pub fn new(interceptor: I) -> Self {\n        Self { interceptor }\n    }\n}\n\nimpl<S, I> Layer<S> for InterceptorLayer<I>\nwhere\n    I: Clone,\n{\n    type Service = InterceptedService<S, I>;\n\n    fn layer(&self, service: S) -> Self::Service {\n        InterceptedService::new(service, self.interceptor.clone())\n    }\n}\n\n/// A service wrapped in an interceptor middleware.\n///\n/// See [`Interceptor`] for more details.\n#[derive(Clone, Copy)]\npub struct InterceptedService<S, I> {\n    inner: S,\n    interceptor: I,\n}\n\nimpl<S, I> InterceptedService<S, I> {\n    /// Create a new `InterceptedService` that wraps `S` and intercepts each request with the\n    /// function `F`.\n    pub fn new(service: S, interceptor: I) -> Self {\n        Self {\n            inner: service,\n            interceptor,\n        }\n    }\n}\n\nimpl<S, I> fmt::Debug for InterceptedService<S, I>\nwhere\n    S: fmt::Debug,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"InterceptedService\")\n            .field(\"inner\", &self.inner)\n            .field(\"f\", &format_args!(\"{}\", std::any::type_name::<I>()))\n            .finish()\n    }\n}\n\nimpl<S, I, ReqBody, ResBody> Service<http::Request<ReqBody>> for InterceptedService<S, I>\nwhere\n    S: Service<http::Request<ReqBody>, Response = http::Response<ResBody>>,\n    I: Interceptor,\n{\n    type Response = http::Response<ResponseBody<ResBody>>;\n    type Error = S::Error;\n    type Future = ResponseFuture<S::Future>;\n\n    #[inline]\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, req: http::Request<ReqBody>) -> Self::Future {\n        // It is bad practice to modify the body (i.e. Message) of the request via an interceptor.\n        // To avoid exposing the body of the request to the interceptor function, we first remove it\n        // here, allow the interceptor to modify the metadata and extensions, and then recreate the\n        // HTTP request with the body. Tonic requests do not preserve the URI, HTTP version, and\n        // HTTP method of the HTTP request, so we extract them here and then add them back in below.\n        let uri = req.uri().clone();\n        let method = req.method().clone();\n        let version = req.version();\n        let req = crate::Request::from_http(req);\n        let (metadata, extensions, msg) = req.into_parts();\n\n        match self\n            .interceptor\n            .call(crate::Request::from_parts(metadata, extensions, ()))\n        {\n            Ok(req) => {\n                let (metadata, extensions, _) = req.into_parts();\n                let req = crate::Request::from_parts(metadata, extensions, msg);\n                let req = req.into_http(uri, method, version, SanitizeHeaders::No);\n                ResponseFuture::future(self.inner.call(req))\n            }\n            Err(status) => ResponseFuture::status(status),\n        }\n    }\n}\n\n// required to use `InterceptedService` with `Router`\nimpl<S, I> crate::server::NamedService for InterceptedService<S, I>\nwhere\n    S: crate::server::NamedService,\n{\n    const NAME: &'static str = S::NAME;\n}\n\n/// Response future for [`InterceptedService`].\n#[pin_project]\n#[derive(Debug)]\npub struct ResponseFuture<F> {\n    #[pin]\n    kind: Kind<F>,\n}\n\nimpl<F> ResponseFuture<F> {\n    fn future(future: F) -> Self {\n        Self {\n            kind: Kind::Future(future),\n        }\n    }\n\n    fn status(status: Status) -> Self {\n        Self {\n            kind: Kind::Status(Some(status)),\n        }\n    }\n}\n\n#[pin_project(project = KindProj)]\n#[derive(Debug)]\nenum Kind<F> {\n    Future(#[pin] F),\n    Status(Option<Status>),\n}\n\nimpl<F, E, B> Future for ResponseFuture<F>\nwhere\n    F: Future<Output = Result<http::Response<B>, E>>,\n{\n    type Output = Result<http::Response<ResponseBody<B>>, E>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match self.project().kind.project() {\n            KindProj::Future(future) => future.poll(cx).map_ok(|res| res.map(ResponseBody::wrap)),\n            KindProj::Status(status) => {\n                let (parts, ()) = status.take().unwrap().into_http::<()>().into_parts();\n                let response = http::Response::from_parts(parts, ResponseBody::<B>::empty());\n                Poll::Ready(Ok(response))\n            }\n        }\n    }\n}\n\n/// Response body for [`InterceptedService`].\n#[pin_project]\n#[derive(Debug)]\npub struct ResponseBody<B> {\n    #[pin]\n    kind: ResponseBodyKind<B>,\n}\n\n#[pin_project(project = ResponseBodyKindProj)]\n#[derive(Debug)]\nenum ResponseBodyKind<B> {\n    Empty,\n    Wrap(#[pin] B),\n}\n\nimpl<B> ResponseBody<B> {\n    fn new(kind: ResponseBodyKind<B>) -> Self {\n        Self { kind }\n    }\n\n    fn empty() -> Self {\n        Self::new(ResponseBodyKind::Empty)\n    }\n\n    fn wrap(body: B) -> Self {\n        Self::new(ResponseBodyKind::Wrap(body))\n    }\n}\n\nimpl<B: http_body::Body> http_body::Body for ResponseBody<B> {\n    type Data = B::Data;\n    type Error = B::Error;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {\n        match self.project().kind.project() {\n            ResponseBodyKindProj::Empty => Poll::Ready(None),\n            ResponseBodyKindProj::Wrap(body) => body.poll_frame(cx),\n        }\n    }\n\n    fn size_hint(&self) -> http_body::SizeHint {\n        match &self.kind {\n            ResponseBodyKind::Empty => http_body::SizeHint::with_exact(0),\n            ResponseBodyKind::Wrap(body) => body.size_hint(),\n        }\n    }\n\n    fn is_end_stream(&self) -> bool {\n        match &self.kind {\n            ResponseBodyKind::Empty => true,\n            ResponseBodyKind::Wrap(body) => body.is_end_stream(),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use tower::ServiceExt;\n\n    #[tokio::test]\n    async fn doesnt_remove_headers_from_requests() {\n        let svc = tower::service_fn(|request: http::Request<()>| async move {\n            assert_eq!(\n                request\n                    .headers()\n                    .get(\"user-agent\")\n                    .expect(\"missing in leaf service\"),\n                \"test-tonic\"\n            );\n\n            Ok::<_, Status>(http::Response::new(()))\n        });\n\n        let svc = InterceptedService::new(svc, |request: crate::Request<()>| {\n            assert_eq!(\n                request\n                    .metadata()\n                    .get(\"user-agent\")\n                    .expect(\"missing in interceptor\"),\n                \"test-tonic\"\n            );\n\n            Ok(request)\n        });\n\n        let request = http::Request::builder()\n            .header(\"user-agent\", \"test-tonic\")\n            .body(())\n            .unwrap();\n\n        svc.oneshot(request).await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn handles_intercepted_status_as_response() {\n        let message = \"Blocked by the interceptor\";\n        let expected = Status::permission_denied(message).into_http::<()>();\n\n        let svc = tower::service_fn(|_: http::Request<()>| async {\n            Ok::<_, Status>(http::Response::new(()))\n        });\n\n        let svc = InterceptedService::new(svc, |_: crate::Request<()>| {\n            Err(Status::permission_denied(message))\n        });\n\n        let request = http::Request::builder().body(()).unwrap();\n        let response = svc.oneshot(request).await.unwrap();\n\n        assert_eq!(expected.status(), response.status());\n        assert_eq!(expected.version(), response.version());\n        assert_eq!(expected.headers(), response.headers());\n    }\n\n    #[tokio::test]\n    async fn doesnt_change_http_method() {\n        let svc = tower::service_fn(|request: http::Request<()>| async move {\n            assert_eq!(request.method(), http::Method::OPTIONS);\n\n            Ok::<_, hyper::Error>(hyper::Response::new(()))\n        });\n\n        let svc = InterceptedService::new(svc, Ok);\n\n        let request = http::Request::builder()\n            .method(http::Method::OPTIONS)\n            .body(())\n            .unwrap();\n\n        svc.oneshot(request).await.unwrap();\n    }\n}\n"
  },
  {
    "path": "tonic/src/service/layered.rs",
    "content": "use std::{\n    marker::PhantomData,\n    task::{Context, Poll},\n};\n\nuse tower_layer::Layer;\nuse tower_service::Service;\n\nuse crate::server::NamedService;\n\n/// A layered service to propagate [`NamedService`] implementation.\n#[derive(Debug, Clone)]\npub struct Layered<S, T> {\n    inner: S,\n    _ty: PhantomData<T>,\n}\n\nimpl<S, T: NamedService> NamedService for Layered<S, T> {\n    const NAME: &'static str = T::NAME;\n}\n\nimpl<Req, S, T> Service<Req> for Layered<S, T>\nwhere\n    S: Service<Req>,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, req: Req) -> Self::Future {\n        self.inner.call(req)\n    }\n}\n\n/// Extension trait which adds utility methods to types which implement [`tower_layer::Layer`].\npub trait LayerExt<L>: sealed::Sealed {\n    /// Applies the layer to a service and wraps it in [`Layered`].\n    fn named_layer<S>(&self, service: S) -> Layered<L::Service, S>\n    where\n        L: Layer<S>;\n}\n\nimpl<L> LayerExt<L> for L {\n    fn named_layer<S>(&self, service: S) -> Layered<<L>::Service, S>\n    where\n        L: Layer<S>,\n    {\n        Layered {\n            inner: self.layer(service),\n            _ty: PhantomData,\n        }\n    }\n}\n\nmod sealed {\n    pub trait Sealed {}\n    impl<T> Sealed for T {}\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[derive(Debug, Default)]\n    struct TestService {}\n\n    const TEST_SERVICE_NAME: &str = \"test-service-name\";\n\n    impl NamedService for TestService {\n        const NAME: &'static str = TEST_SERVICE_NAME;\n    }\n\n    // Checks if the argument implements `NamedService` and returns the implemented `NAME`.\n    fn get_name_of_named_service<S: NamedService>(_s: &S) -> &'static str {\n        S::NAME\n    }\n\n    #[test]\n    fn named_service_is_propagated_to_layered() {\n        use std::time::Duration;\n        use tower::{limit::ConcurrencyLimitLayer, timeout::TimeoutLayer};\n\n        let layered = TimeoutLayer::new(Duration::from_secs(5)).named_layer(TestService::default());\n        assert_eq!(get_name_of_named_service(&layered), TEST_SERVICE_NAME);\n\n        let layered = ConcurrencyLimitLayer::new(3).named_layer(layered);\n        assert_eq!(get_name_of_named_service(&layered), TEST_SERVICE_NAME);\n    }\n}\n"
  },
  {
    "path": "tonic/src/service/mod.rs",
    "content": "//! Utilities for using Tower services with Tonic.\n\npub mod interceptor;\npub(crate) mod layered;\n#[cfg(feature = \"router\")]\npub(crate) mod router;\n\n#[doc(inline)]\npub use self::interceptor::{Interceptor, InterceptorLayer};\npub use self::layered::{LayerExt, Layered};\n#[doc(inline)]\n#[cfg(feature = \"router\")]\npub use self::router::{Routes, RoutesBuilder};\n#[cfg(feature = \"router\")]\npub use axum::{Router as AxumRouter, body::Body as AxumBody};\n\npub mod recover_error;\npub use self::recover_error::{RecoverError, RecoverErrorLayer};\n"
  },
  {
    "path": "tonic/src/service/recover_error.rs",
    "content": "//! Middleware which recovers from error.\n\nuse std::{\n    fmt,\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll, ready},\n};\n\nuse http::Response;\nuse pin_project::pin_project;\nuse tower_layer::Layer;\nuse tower_service::Service;\n\nuse crate::Status;\n\n/// Layer which applies the [`RecoverError`] middleware.\n#[derive(Debug, Default, Clone)]\npub struct RecoverErrorLayer {\n    _priv: (),\n}\n\nimpl RecoverErrorLayer {\n    /// Create a new `RecoverErrorLayer`.\n    pub fn new() -> Self {\n        Self { _priv: () }\n    }\n}\n\nimpl<S> Layer<S> for RecoverErrorLayer {\n    type Service = RecoverError<S>;\n\n    fn layer(&self, inner: S) -> Self::Service {\n        RecoverError::new(inner)\n    }\n}\n\n/// Middleware that attempts to recover from service errors by turning them into a response built\n/// from the `Status`.\n#[derive(Debug, Clone)]\npub struct RecoverError<S> {\n    inner: S,\n}\n\nimpl<S> RecoverError<S> {\n    /// Create a new `RecoverError` middleware.\n    pub fn new(inner: S) -> Self {\n        Self { inner }\n    }\n}\n\nimpl<S, Req, ResBody> Service<Req> for RecoverError<S>\nwhere\n    S: Service<Req, Response = Response<ResBody>>,\n    S::Error: Into<crate::BoxError>,\n{\n    type Response = Response<ResponseBody<ResBody>>;\n    type Error = crate::BoxError;\n    type Future = ResponseFuture<S::Future>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: Req) -> Self::Future {\n        ResponseFuture {\n            inner: self.inner.call(req),\n        }\n    }\n}\n\n/// Response future for [`RecoverError`].\n#[pin_project]\npub struct ResponseFuture<F> {\n    #[pin]\n    inner: F,\n}\n\nimpl<F> fmt::Debug for ResponseFuture<F> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ResponseFuture\").finish()\n    }\n}\n\nimpl<F, E, ResBody> Future for ResponseFuture<F>\nwhere\n    F: Future<Output = Result<Response<ResBody>, E>>,\n    E: Into<crate::BoxError>,\n{\n    type Output = Result<Response<ResponseBody<ResBody>>, crate::BoxError>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match ready!(self.project().inner.poll(cx)) {\n            Ok(response) => {\n                let response = response.map(ResponseBody::full);\n                Poll::Ready(Ok(response))\n            }\n            Err(err) => match Status::try_from_error(err.into()) {\n                Ok(status) => {\n                    let (parts, ()) = status.into_http::<()>().into_parts();\n                    let res = Response::from_parts(parts, ResponseBody::empty());\n                    Poll::Ready(Ok(res))\n                }\n                Err(err) => Poll::Ready(Err(err)),\n            },\n        }\n    }\n}\n\n/// Response body for [`RecoverError`].\n#[pin_project]\npub struct ResponseBody<B> {\n    #[pin]\n    inner: Option<B>,\n}\n\nimpl<B> fmt::Debug for ResponseBody<B> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ResponseBody\").finish()\n    }\n}\n\nimpl<B> ResponseBody<B> {\n    fn full(inner: B) -> Self {\n        Self { inner: Some(inner) }\n    }\n\n    const fn empty() -> Self {\n        Self { inner: None }\n    }\n}\n\nimpl<B> http_body::Body for ResponseBody<B>\nwhere\n    B: http_body::Body,\n{\n    type Data = B::Data;\n    type Error = B::Error;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {\n        match self.project().inner.as_pin_mut() {\n            Some(b) => b.poll_frame(cx),\n            None => Poll::Ready(None),\n        }\n    }\n\n    fn is_end_stream(&self) -> bool {\n        match &self.inner {\n            Some(b) => b.is_end_stream(),\n            None => true,\n        }\n    }\n\n    fn size_hint(&self) -> http_body::SizeHint {\n        match &self.inner {\n            Some(body) => body.size_hint(),\n            None => http_body::SizeHint::with_exact(0),\n        }\n    }\n}\n"
  },
  {
    "path": "tonic/src/service/router.rs",
    "content": "use crate::{Status, body::Body, server::NamedService};\nuse http::{Request, Response};\nuse std::{\n    convert::Infallible,\n    fmt,\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tower::{Service, ServiceExt};\n\n/// A [`Service`] router.\n#[derive(Debug, Clone)]\npub struct Routes {\n    router: axum::Router,\n}\n\n#[derive(Debug, Default, Clone)]\n/// Allows adding new services to routes by passing a mutable reference to this builder.\npub struct RoutesBuilder {\n    routes: Option<Routes>,\n}\n\nimpl RoutesBuilder {\n    /// Add a new service.\n    pub fn add_service<S>(&mut self, svc: S) -> &mut Self\n    where\n        S: Service<Request<Body>, Error = Infallible>\n            + NamedService\n            + Clone\n            + Send\n            + Sync\n            + 'static,\n        S::Response: axum::response::IntoResponse,\n        S::Future: Send + 'static,\n    {\n        let routes = self.routes.take().unwrap_or_default();\n        self.routes.replace(routes.add_service(svc));\n        self\n    }\n\n    /// Returns the routes with added services or empty [`Routes`] if no service was added\n    pub fn routes(self) -> Routes {\n        self.routes.unwrap_or_default()\n    }\n}\n\nimpl Default for Routes {\n    fn default() -> Self {\n        Self {\n            router: axum::Router::new().fallback(unimplemented),\n        }\n    }\n}\n\nimpl Routes {\n    /// Create a new routes with `svc` already added to it.\n    pub fn new<S>(svc: S) -> Self\n    where\n        S: Service<Request<Body>, Error = Infallible>\n            + NamedService\n            + Clone\n            + Send\n            + Sync\n            + 'static,\n        S::Response: axum::response::IntoResponse,\n        S::Future: Send + 'static,\n    {\n        Self::default().add_service(svc)\n    }\n\n    /// Create a new empty builder.\n    pub fn builder() -> RoutesBuilder {\n        RoutesBuilder::default()\n    }\n\n    /// Add a new service.\n    pub fn add_service<S>(mut self, svc: S) -> Self\n    where\n        S: Service<Request<Body>, Error = Infallible>\n            + NamedService\n            + Clone\n            + Send\n            + Sync\n            + 'static,\n        S::Response: axum::response::IntoResponse,\n        S::Future: Send + 'static,\n    {\n        self.router = self.router.route_service(\n            &format!(\"/{}/{{*rest}}\", S::NAME),\n            svc.map_request(|req: Request<axum::body::Body>| req.map(Body::new)),\n        );\n        self\n    }\n\n    /// This makes axum perform update some internals of the router that improves perf.\n    ///\n    /// See <https://docs.rs/axum/latest/axum/routing/struct.Router.html#a-note-about-performance>\n    pub fn prepare(self) -> Self {\n        Self {\n            router: self.router.with_state(()),\n        }\n    }\n\n    /// Convert this `Routes` into an [`axum::Router`].\n    pub fn into_axum_router(self) -> axum::Router {\n        self.router\n    }\n\n    /// Get a mutable reference to the [`axum::Router`].\n    pub fn axum_router_mut(&mut self) -> &mut axum::Router {\n        &mut self.router\n    }\n}\n\nimpl From<Routes> for RoutesBuilder {\n    fn from(routes: Routes) -> Self {\n        Self {\n            routes: Some(routes),\n        }\n    }\n}\n\nimpl From<axum::Router> for RoutesBuilder {\n    fn from(router: axum::Router) -> Self {\n        Self {\n            routes: Some(router.into()),\n        }\n    }\n}\n\nimpl From<axum::Router> for Routes {\n    fn from(router: axum::Router) -> Self {\n        Self { router }\n    }\n}\n\nasync fn unimplemented() -> Response<Body> {\n    let (parts, ()) = Status::unimplemented(\"\").into_http::<()>().into_parts();\n    Response::from_parts(parts, Body::empty())\n}\n\nimpl<B> Service<Request<B>> for Routes\nwhere\n    B: http_body::Body<Data = bytes::Bytes> + Send + 'static,\n    B::Error: Into<crate::BoxError>,\n{\n    type Response = Response<Body>;\n    type Error = Infallible;\n    type Future = RoutesFuture;\n\n    #[inline]\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Service::<Request<B>>::poll_ready(&mut self.router, cx)\n    }\n\n    fn call(&mut self, req: Request<B>) -> Self::Future {\n        RoutesFuture(self.router.call(req))\n    }\n}\n\npub struct RoutesFuture(axum::routing::future::RouteFuture<Infallible>);\n\nimpl fmt::Debug for RoutesFuture {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_tuple(\"RoutesFuture\").finish()\n    }\n}\n\nimpl Future for RoutesFuture {\n    type Output = Result<Response<Body>, Infallible>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        Pin::new(&mut self.as_mut().0)\n            .poll(cx)\n            .map_ok(|res| res.map(Body::new))\n    }\n}\n"
  },
  {
    "path": "tonic/src/status.rs",
    "content": "use crate::metadata::GRPC_CONTENT_TYPE;\nuse crate::metadata::MetadataMap;\nuse base64::Engine as _;\nuse bytes::Bytes;\nuse http::{\n    HeaderName,\n    header::{HeaderMap, HeaderValue},\n};\nuse percent_encoding::{AsciiSet, CONTROLS, percent_decode, percent_encode};\nuse std::{borrow::Cow, error::Error, fmt, sync::Arc};\nuse tracing::{debug, trace, warn};\n\nconst ENCODING_SET: &AsciiSet = &CONTROLS\n    .add(b' ')\n    .add(b'\"')\n    .add(b'#')\n    .add(b'%')\n    .add(b'<')\n    .add(b'>')\n    .add(b'`')\n    .add(b'?')\n    .add(b'{')\n    .add(b'}');\n\n/// A gRPC status describing the result of an RPC call.\n///\n/// Values can be created using the `new` function or one of the specialized\n/// associated functions.\n/// ```rust\n/// # use tonic::{Status, Code};\n/// let status1 = Status::new(Code::InvalidArgument, \"name is invalid\");\n/// let status2 = Status::invalid_argument(\"name is invalid\");\n///\n/// assert_eq!(status1.code(), Code::InvalidArgument);\n/// assert_eq!(status1.code(), status2.code());\n/// ```\n#[derive(Clone)]\npub struct Status(Box<StatusInner>);\n\n/// Box the contents of Status to avoid large error variants\n#[derive(Clone)]\nstruct StatusInner {\n    /// The gRPC status code, found in the `grpc-status` header.\n    code: Code,\n    /// A relevant error message, found in the `grpc-message` header.\n    message: String,\n    /// Binary opaque details, found in the `grpc-status-details-bin` header.\n    details: Bytes,\n    /// Custom metadata, found in the user-defined headers.\n    /// If the metadata contains any headers with names reserved either by the gRPC spec\n    /// or by `Status` fields above, they will be ignored.\n    metadata: MetadataMap,\n    /// Optional underlying error.\n    source: Option<Arc<dyn Error + Send + Sync + 'static>>,\n}\n\nimpl StatusInner {\n    fn into_status(self) -> Status {\n        Status(Box::new(self))\n    }\n}\n\n/// gRPC status codes used by [`Status`].\n///\n/// These variants match the [gRPC status codes].\n///\n/// [gRPC status codes]: https://github.com/grpc/grpc/blob/master/doc/statuscodes.md#status-codes-and-their-use-in-grpc\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]\npub enum Code {\n    /// The operation completed successfully.\n    Ok = 0,\n\n    /// The operation was cancelled.\n    Cancelled = 1,\n\n    /// Unknown error.\n    Unknown = 2,\n\n    /// Client specified an invalid argument.\n    InvalidArgument = 3,\n\n    /// Deadline expired before operation could complete.\n    DeadlineExceeded = 4,\n\n    /// Some requested entity was not found.\n    NotFound = 5,\n\n    /// Some entity that we attempted to create already exists.\n    AlreadyExists = 6,\n\n    /// The caller does not have permission to execute the specified operation.\n    PermissionDenied = 7,\n\n    /// Some resource has been exhausted.\n    ResourceExhausted = 8,\n\n    /// The system is not in a state required for the operation's execution.\n    FailedPrecondition = 9,\n\n    /// The operation was aborted.\n    Aborted = 10,\n\n    /// Operation was attempted past the valid range.\n    OutOfRange = 11,\n\n    /// Operation is not implemented or not supported.\n    Unimplemented = 12,\n\n    /// Internal error.\n    Internal = 13,\n\n    /// The service is currently unavailable.\n    Unavailable = 14,\n\n    /// Unrecoverable data loss or corruption.\n    DataLoss = 15,\n\n    /// The request does not have valid authentication credentials\n    Unauthenticated = 16,\n}\n\nimpl Code {\n    /// Get description of this `Code`.\n    /// ```\n    /// fn make_grpc_request() -> tonic::Code {\n    ///     // ...\n    ///     tonic::Code::Ok\n    /// }\n    /// let code = make_grpc_request();\n    /// println!(\"Operation completed. Human readable description: {}\", code.description());\n    /// ```\n    /// If you only need description in `println`, `format`, `log` and other\n    /// formatting contexts, you may want to use `Display` impl for `Code`\n    /// instead.\n    pub fn description(&self) -> &'static str {\n        match self {\n            Code::Ok => \"The operation completed successfully\",\n            Code::Cancelled => \"The operation was cancelled\",\n            Code::Unknown => \"Unknown error\",\n            Code::InvalidArgument => \"Client specified an invalid argument\",\n            Code::DeadlineExceeded => \"Deadline expired before operation could complete\",\n            Code::NotFound => \"Some requested entity was not found\",\n            Code::AlreadyExists => \"Some entity that we attempted to create already exists\",\n            Code::PermissionDenied => {\n                \"The caller does not have permission to execute the specified operation\"\n            }\n            Code::ResourceExhausted => \"Some resource has been exhausted\",\n            Code::FailedPrecondition => {\n                \"The system is not in a state required for the operation's execution\"\n            }\n            Code::Aborted => \"The operation was aborted\",\n            Code::OutOfRange => \"Operation was attempted past the valid range\",\n            Code::Unimplemented => \"Operation is not implemented or not supported\",\n            Code::Internal => \"Internal error\",\n            Code::Unavailable => \"The service is currently unavailable\",\n            Code::DataLoss => \"Unrecoverable data loss or corruption\",\n            Code::Unauthenticated => \"The request does not have valid authentication credentials\",\n        }\n    }\n}\n\nimpl std::fmt::Display for Code {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        std::fmt::Display::fmt(self.description(), f)\n    }\n}\n\n// ===== impl Status =====\n\nimpl Status {\n    /// Create a new `Status` with the associated code and message.\n    pub fn new(code: Code, message: impl Into<String>) -> Status {\n        StatusInner {\n            code,\n            message: message.into(),\n            details: Bytes::new(),\n            metadata: MetadataMap::new(),\n            source: None,\n        }\n        .into_status()\n    }\n\n    /// The operation completed successfully.\n    pub fn ok(message: impl Into<String>) -> Status {\n        Status::new(Code::Ok, message)\n    }\n\n    /// The operation was cancelled (typically by the caller).\n    pub fn cancelled(message: impl Into<String>) -> Status {\n        Status::new(Code::Cancelled, message)\n    }\n\n    /// Unknown error. An example of where this error may be returned is if a\n    /// `Status` value received from another address space belongs to an error-space\n    /// that is not known in this address space. Also errors raised by APIs that\n    /// do not return enough error information may be converted to this error.\n    pub fn unknown(message: impl Into<String>) -> Status {\n        Status::new(Code::Unknown, message)\n    }\n\n    /// Client specified an invalid argument. Note that this differs from\n    /// `FailedPrecondition`. `InvalidArgument` indicates arguments that are\n    /// problematic regardless of the state of the system (e.g., a malformed file\n    /// name).\n    pub fn invalid_argument(message: impl Into<String>) -> Status {\n        Status::new(Code::InvalidArgument, message)\n    }\n\n    /// Deadline expired before operation could complete. For operations that\n    /// change the state of the system, this error may be returned even if the\n    /// operation has completed successfully. For example, a successful response\n    /// from a server could have been delayed long enough for the deadline to\n    /// expire.\n    pub fn deadline_exceeded(message: impl Into<String>) -> Status {\n        Status::new(Code::DeadlineExceeded, message)\n    }\n\n    /// Some requested entity (e.g., file or directory) was not found.\n    pub fn not_found(message: impl Into<String>) -> Status {\n        Status::new(Code::NotFound, message)\n    }\n\n    /// Some entity that we attempted to create (e.g., file or directory) already\n    /// exists.\n    pub fn already_exists(message: impl Into<String>) -> Status {\n        Status::new(Code::AlreadyExists, message)\n    }\n\n    /// The caller does not have permission to execute the specified operation.\n    /// `PermissionDenied` must not be used for rejections caused by exhausting\n    /// some resource (use `ResourceExhausted` instead for those errors).\n    /// `PermissionDenied` must not be used if the caller cannot be identified\n    /// (use `Unauthenticated` instead for those errors).\n    pub fn permission_denied(message: impl Into<String>) -> Status {\n        Status::new(Code::PermissionDenied, message)\n    }\n\n    /// Some resource has been exhausted, perhaps a per-user quota, or perhaps\n    /// the entire file system is out of space.\n    pub fn resource_exhausted(message: impl Into<String>) -> Status {\n        Status::new(Code::ResourceExhausted, message)\n    }\n\n    /// Operation was rejected because the system is not in a state required for\n    /// the operation's execution. For example, directory to be deleted may be\n    /// non-empty, an rmdir operation is applied to a non-directory, etc.\n    ///\n    /// A litmus test that may help a service implementor in deciding between\n    /// `FailedPrecondition`, `Aborted`, and `Unavailable`:\n    /// (a) Use `Unavailable` if the client can retry just the failing call.\n    /// (b) Use `Aborted` if the client should retry at a higher-level (e.g.,\n    ///     restarting a read-modify-write sequence).\n    /// (c) Use `FailedPrecondition` if the client should not retry until the\n    ///     system state has been explicitly fixed.  E.g., if an \"rmdir\" fails\n    ///     because the directory is non-empty, `FailedPrecondition` should be\n    ///     returned since the client should not retry unless they have first\n    ///     fixed up the directory by deleting files from it.\n    pub fn failed_precondition(message: impl Into<String>) -> Status {\n        Status::new(Code::FailedPrecondition, message)\n    }\n\n    /// The operation was aborted, typically due to a concurrency issue like\n    /// sequencer check failures, transaction aborts, etc.\n    ///\n    /// See litmus test above for deciding between `FailedPrecondition`,\n    /// `Aborted`, and `Unavailable`.\n    pub fn aborted(message: impl Into<String>) -> Status {\n        Status::new(Code::Aborted, message)\n    }\n\n    /// Operation was attempted past the valid range. E.g., seeking or reading\n    /// past end of file.\n    ///\n    /// Unlike `InvalidArgument`, this error indicates a problem that may be\n    /// fixed if the system state changes. For example, a 32-bit file system will\n    /// generate `InvalidArgument` if asked to read at an offset that is not in the\n    /// range [0,2^32-1], but it will generate `OutOfRange` if asked to read from\n    /// an offset past the current file size.\n    ///\n    /// There is a fair bit of overlap between `FailedPrecondition` and\n    /// `OutOfRange`. We recommend using `OutOfRange` (the more specific error)\n    /// when it applies so that callers who are iterating through a space can\n    /// easily look for an `OutOfRange` error to detect when they are done.\n    pub fn out_of_range(message: impl Into<String>) -> Status {\n        Status::new(Code::OutOfRange, message)\n    }\n\n    /// Operation is not implemented or not supported/enabled in this service.\n    pub fn unimplemented(message: impl Into<String>) -> Status {\n        Status::new(Code::Unimplemented, message)\n    }\n\n    /// Internal errors. Means some invariants expected by underlying system has\n    /// been broken. If you see one of these errors, something is very broken.\n    pub fn internal(message: impl Into<String>) -> Status {\n        Status::new(Code::Internal, message)\n    }\n\n    /// The service is currently unavailable.  This is a most likely a transient\n    /// condition and may be corrected by retrying with a back-off.\n    ///\n    /// See litmus test above for deciding between `FailedPrecondition`,\n    /// `Aborted`, and `Unavailable`.\n    pub fn unavailable(message: impl Into<String>) -> Status {\n        Status::new(Code::Unavailable, message)\n    }\n\n    /// Unrecoverable data loss or corruption.\n    pub fn data_loss(message: impl Into<String>) -> Status {\n        Status::new(Code::DataLoss, message)\n    }\n\n    /// The request does not have valid authentication credentials for the\n    /// operation.\n    pub fn unauthenticated(message: impl Into<String>) -> Status {\n        Status::new(Code::Unauthenticated, message)\n    }\n\n    pub(crate) fn from_error_generic(\n        err: impl Into<Box<dyn Error + Send + Sync + 'static>>,\n    ) -> Status {\n        Self::from_error(err.into())\n    }\n\n    /// Create a `Status` from various types of `Error`.\n    ///\n    /// Inspects the error source chain for recognizable errors, including statuses, HTTP2, and\n    /// hyper, and attempts to maps them to a `Status`, or else returns an Unknown `Status`.\n    pub fn from_error(err: Box<dyn Error + Send + Sync + 'static>) -> Status {\n        Status::try_from_error(err).unwrap_or_else(|err| {\n            let mut status = Status::new(Code::Unknown, err.to_string());\n            status.0.source = Some(err.into());\n            status\n        })\n    }\n\n    /// Create a `Status` from various types of `Error`.\n    ///\n    /// Returns the error if a status could not be created.\n    ///\n    /// # Downcast stability\n    /// This function does not provide any stability guarantees around how it will downcast errors into\n    /// status codes.\n    pub fn try_from_error(\n        err: Box<dyn Error + Send + Sync + 'static>,\n    ) -> Result<Status, Box<dyn Error + Send + Sync + 'static>> {\n        let err = match err.downcast::<Status>() {\n            Ok(status) => {\n                return Ok(*status);\n            }\n            Err(err) => err,\n        };\n\n        #[cfg(feature = \"server\")]\n        let err = match err.downcast::<h2::Error>() {\n            Ok(h2) => {\n                return Ok(Status::from_h2_error(h2));\n            }\n            Err(err) => err,\n        };\n\n        // If the load shed middleware is enabled, respond to\n        // service overloaded with an appropriate grpc status.\n        #[cfg(feature = \"server\")]\n        let err = match err.downcast::<tower::load_shed::error::Overloaded>() {\n            Ok(_) => {\n                return Ok(Status::resource_exhausted(\n                    \"Too many active requests for the connection\",\n                ));\n            }\n            Err(err) => err,\n        };\n\n        if let Some(mut status) = find_status_in_source_chain(&*err) {\n            status.0.source = Some(err.into());\n            return Ok(status);\n        }\n\n        Err(err)\n    }\n\n    // FIXME: bubble this into `transport` and expose generic http2 reasons.\n    #[cfg(feature = \"server\")]\n    fn from_h2_error(err: Box<h2::Error>) -> Status {\n        let code = Self::code_from_h2(&err);\n\n        let mut status = Self::new(code, format!(\"h2 protocol error: {err}\"));\n        status.0.source = Some(Arc::new(*err));\n        status\n    }\n\n    #[cfg(feature = \"server\")]\n    fn code_from_h2(err: &h2::Error) -> Code {\n        // See https://github.com/grpc/grpc/blob/3977c30/doc/PROTOCOL-HTTP2.md#errors\n        match err.reason() {\n            Some(h2::Reason::NO_ERROR)\n            | Some(h2::Reason::PROTOCOL_ERROR)\n            | Some(h2::Reason::INTERNAL_ERROR)\n            | Some(h2::Reason::FLOW_CONTROL_ERROR)\n            | Some(h2::Reason::SETTINGS_TIMEOUT)\n            | Some(h2::Reason::COMPRESSION_ERROR)\n            | Some(h2::Reason::CONNECT_ERROR) => Code::Internal,\n            Some(h2::Reason::REFUSED_STREAM) => Code::Unavailable,\n            Some(h2::Reason::CANCEL) => Code::Cancelled,\n            Some(h2::Reason::ENHANCE_YOUR_CALM) => Code::ResourceExhausted,\n            Some(h2::Reason::INADEQUATE_SECURITY) => Code::PermissionDenied,\n\n            _ => Code::Unknown,\n        }\n    }\n\n    #[cfg(feature = \"server\")]\n    fn to_h2_error(&self) -> h2::Error {\n        // conservatively transform to h2 error codes...\n        let reason = match self.code() {\n            Code::Cancelled => h2::Reason::CANCEL,\n            _ => h2::Reason::INTERNAL_ERROR,\n        };\n\n        reason.into()\n    }\n\n    /// Handles hyper errors specifically, which expose a number of different parameters about the\n    /// http stream's error: https://docs.rs/hyper/0.14.11/hyper/struct.Error.html.\n    ///\n    /// Returns Some if there's a way to handle the error, or None if the information from this\n    /// hyper error, but perhaps not its source, should be ignored.\n    #[cfg(any(feature = \"server\", feature = \"channel\"))]\n    fn from_hyper_error(err: &hyper::Error) -> Option<Status> {\n        // is_timeout results from hyper's keep-alive logic\n        // (https://docs.rs/hyper/0.14.11/src/hyper/error.rs.html#192-194).  Per the grpc spec\n        // > An expired client initiated PING will cause all calls to be closed with an UNAVAILABLE\n        // > status. Note that the frequency of PINGs is highly dependent on the network\n        // > environment, implementations are free to adjust PING frequency based on network and\n        // > application requirements, which is why it's mapped to unavailable here.\n        if err.is_timeout() {\n            return Some(Status::unavailable(err.to_string()));\n        }\n\n        if err.is_canceled() {\n            return Some(Status::cancelled(err.to_string()));\n        }\n\n        #[cfg(feature = \"server\")]\n        if let Some(h2_err) = err.source().and_then(|e| e.downcast_ref::<h2::Error>()) {\n            let code = Status::code_from_h2(h2_err);\n            let status = Self::new(code, format!(\"h2 protocol error: {err}\"));\n\n            return Some(status);\n        }\n\n        None\n    }\n\n    pub(crate) fn map_error<E>(err: E) -> Status\n    where\n        E: Into<Box<dyn Error + Send + Sync>>,\n    {\n        let err: Box<dyn Error + Send + Sync> = err.into();\n        Status::from_error(err)\n    }\n\n    /// Extract a `Status` from a hyper `HeaderMap`.\n    pub fn from_header_map(header_map: &HeaderMap) -> Option<Status> {\n        let code = Code::from_bytes(header_map.get(Self::GRPC_STATUS)?.as_ref());\n\n        let error_message = match header_map.get(Self::GRPC_MESSAGE) {\n            Some(header) => percent_decode(header.as_bytes())\n                .decode_utf8()\n                .map(|cow| cow.to_string()),\n            None => Ok(String::new()),\n        };\n\n        let details = match header_map.get(Self::GRPC_STATUS_DETAILS) {\n            Some(header) => crate::util::base64::STANDARD\n                .decode(header.as_bytes())\n                .expect(\"Invalid status header, expected base64 encoded value\")\n                .into(),\n            None => Bytes::new(),\n        };\n\n        let other_headers = {\n            let mut header_map = header_map.clone();\n            header_map.remove(Self::GRPC_STATUS);\n            header_map.remove(Self::GRPC_MESSAGE);\n            header_map.remove(Self::GRPC_STATUS_DETAILS);\n            header_map\n        };\n\n        let (code, message) = match error_message {\n            Ok(message) => (code, message),\n            Err(e) => {\n                let error_message = format!(\"Error deserializing status message header: {e}\");\n                warn!(error_message);\n                (Code::Unknown, error_message)\n            }\n        };\n\n        Some(\n            StatusInner {\n                code,\n                message,\n                details,\n                metadata: MetadataMap::from_headers(other_headers),\n                source: None,\n            }\n            .into_status(),\n        )\n    }\n\n    /// Get the gRPC `Code` of this `Status`.\n    pub fn code(&self) -> Code {\n        self.0.code\n    }\n\n    /// Get the text error message of this `Status`.\n    pub fn message(&self) -> &str {\n        &self.0.message\n    }\n\n    /// Get the opaque error details of this `Status`.\n    pub fn details(&self) -> &[u8] {\n        &self.0.details\n    }\n\n    /// Get a reference to the custom metadata.\n    pub fn metadata(&self) -> &MetadataMap {\n        &self.0.metadata\n    }\n\n    /// Get a mutable reference to the custom metadata.\n    pub fn metadata_mut(&mut self) -> &mut MetadataMap {\n        &mut self.0.metadata\n    }\n\n    pub(crate) fn to_header_map(&self) -> Result<HeaderMap, Self> {\n        let mut header_map = HeaderMap::with_capacity(3 + self.0.metadata.len());\n        self.add_header(&mut header_map)?;\n        Ok(header_map)\n    }\n\n    /// Add headers from this `Status` into `header_map`.\n    pub fn add_header(&self, header_map: &mut HeaderMap) -> Result<(), Self> {\n        header_map.extend(self.0.metadata.clone().into_sanitized_headers());\n\n        header_map.insert(Self::GRPC_STATUS, self.0.code.to_header_value());\n\n        if !self.0.message.is_empty() {\n            let to_write = Bytes::copy_from_slice(\n                Cow::from(percent_encode(self.message().as_bytes(), ENCODING_SET)).as_bytes(),\n            );\n\n            header_map.insert(\n                Self::GRPC_MESSAGE,\n                HeaderValue::from_maybe_shared(to_write).map_err(invalid_header_value_byte)?,\n            );\n        }\n\n        if !self.0.details.is_empty() {\n            let details = crate::util::base64::STANDARD_NO_PAD.encode(&self.0.details[..]);\n\n            header_map.insert(\n                Self::GRPC_STATUS_DETAILS,\n                HeaderValue::from_maybe_shared(details).map_err(invalid_header_value_byte)?,\n            );\n        }\n\n        Ok(())\n    }\n\n    /// Create a new `Status` with the associated code, message, and binary details field.\n    pub fn with_details(code: Code, message: impl Into<String>, details: Bytes) -> Status {\n        Self::with_details_and_metadata(code, message, details, MetadataMap::new())\n    }\n\n    /// Create a new `Status` with the associated code, message, and custom metadata\n    pub fn with_metadata(code: Code, message: impl Into<String>, metadata: MetadataMap) -> Status {\n        Self::with_details_and_metadata(code, message, Bytes::new(), metadata)\n    }\n\n    /// Create a new `Status` with the associated code, message, binary details field and custom metadata\n    pub fn with_details_and_metadata(\n        code: Code,\n        message: impl Into<String>,\n        details: Bytes,\n        metadata: MetadataMap,\n    ) -> Status {\n        StatusInner {\n            code,\n            message: message.into(),\n            details,\n            metadata,\n            source: None,\n        }\n        .into_status()\n    }\n\n    /// Add a source error to this status.\n    pub fn set_source(&mut self, source: Arc<dyn Error + Send + Sync + 'static>) -> &mut Status {\n        self.0.source = Some(source);\n        self\n    }\n\n    /// Build an `http::Response` from the given `Status`.\n    pub fn into_http<B: Default>(self) -> http::Response<B> {\n        let mut response = http::Response::new(B::default());\n        response\n            .headers_mut()\n            .insert(http::header::CONTENT_TYPE, GRPC_CONTENT_TYPE);\n        self.add_header(response.headers_mut()).unwrap();\n        response.extensions_mut().insert(self);\n        response\n    }\n\n    #[doc(hidden)]\n    pub const GRPC_STATUS: HeaderName = HeaderName::from_static(\"grpc-status\");\n    #[doc(hidden)]\n    pub const GRPC_MESSAGE: HeaderName = HeaderName::from_static(\"grpc-message\");\n    #[doc(hidden)]\n    pub const GRPC_STATUS_DETAILS: HeaderName = HeaderName::from_static(\"grpc-status-details-bin\");\n}\n\nfn find_status_in_source_chain(err: &(dyn Error + 'static)) -> Option<Status> {\n    let mut source = Some(err);\n\n    while let Some(err) = source {\n        if let Some(status) = err.downcast_ref::<Status>() {\n            return Some(\n                StatusInner {\n                    code: status.0.code,\n                    message: status.0.message.clone(),\n                    details: status.0.details.clone(),\n                    metadata: status.0.metadata.clone(),\n                    // Since `Status` is not `Clone`, any `source` on the original Status\n                    // cannot be cloned so must remain with the original `Status`.\n                    source: None,\n                }\n                .into_status(),\n            );\n        }\n\n        if let Some(timeout) = err.downcast_ref::<TimeoutExpired>() {\n            return Some(Status::cancelled(timeout.to_string()));\n        }\n\n        // If we are unable to connect to the server, map this to UNAVAILABLE.  This is\n        // consistent with the behavior of a C++ gRPC client when the server is not running, and\n        // matches the spec of:\n        // > The service is currently unavailable. This is most likely a transient condition that\n        // > can be corrected if retried with a backoff.\n        if let Some(connect) = err.downcast_ref::<ConnectError>() {\n            return Some(Status::unavailable(connect.to_string()));\n        }\n\n        #[cfg(any(feature = \"server\", feature = \"channel\"))]\n        if let Some(hyper) = err\n            .downcast_ref::<hyper::Error>()\n            .and_then(Status::from_hyper_error)\n        {\n            return Some(hyper);\n        }\n\n        source = err.source();\n    }\n\n    None\n}\n\nimpl fmt::Debug for Status {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.0.fmt(f)\n    }\n}\n\nimpl fmt::Debug for StatusInner {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        // A manual impl to reduce the noise of frequently empty fields.\n        let mut builder = f.debug_struct(\"Status\");\n\n        builder.field(\"code\", &self.code);\n\n        if !self.message.is_empty() {\n            builder.field(\"message\", &self.message);\n        }\n\n        if !self.details.is_empty() {\n            builder.field(\"details\", &self.details);\n        }\n\n        if !self.metadata.is_empty() {\n            builder.field(\"metadata\", &self.metadata);\n        }\n\n        builder.field(\"source\", &self.source);\n\n        builder.finish()\n    }\n}\n\nfn invalid_header_value_byte<Error: fmt::Display>(err: Error) -> Status {\n    debug!(\"Invalid header: {}\", err);\n    Status::new(\n        Code::Internal,\n        \"Couldn't serialize non-text grpc status header\".to_string(),\n    )\n}\n\n#[cfg(feature = \"server\")]\nimpl From<h2::Error> for Status {\n    fn from(err: h2::Error) -> Self {\n        Status::from_h2_error(Box::new(err))\n    }\n}\n\n#[cfg(feature = \"server\")]\nimpl From<Status> for h2::Error {\n    fn from(status: Status) -> Self {\n        status.to_h2_error()\n    }\n}\n\nimpl From<std::io::Error> for Status {\n    fn from(err: std::io::Error) -> Self {\n        use std::io::ErrorKind;\n        let code = match err.kind() {\n            ErrorKind::BrokenPipe\n            | ErrorKind::WouldBlock\n            | ErrorKind::WriteZero\n            | ErrorKind::Interrupted => Code::Internal,\n            ErrorKind::ConnectionRefused\n            | ErrorKind::ConnectionReset\n            | ErrorKind::NotConnected\n            | ErrorKind::AddrInUse\n            | ErrorKind::AddrNotAvailable => Code::Unavailable,\n            ErrorKind::AlreadyExists => Code::AlreadyExists,\n            ErrorKind::ConnectionAborted => Code::Aborted,\n            ErrorKind::InvalidData => Code::DataLoss,\n            ErrorKind::InvalidInput => Code::InvalidArgument,\n            ErrorKind::NotFound => Code::NotFound,\n            ErrorKind::PermissionDenied => Code::PermissionDenied,\n            ErrorKind::TimedOut => Code::DeadlineExceeded,\n            ErrorKind::UnexpectedEof => Code::OutOfRange,\n            _ => Code::Unknown,\n        };\n        Status::new(code, err.to_string())\n    }\n}\n\nimpl fmt::Display for Status {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"code: '{}'\", self.code())?;\n\n        if !self.message().is_empty() {\n            write!(f, \", message: {:?}\", self.message())?;\n        }\n        // We intentionally omit `self.details` since it's binary data, not fit for human eyes.\n        // Additionally, `self.metadata` contains low-level details that only belong in the `Debug`\n        // impl.\n        if let Some(source) = self.source() {\n            write!(f, \", source: {source:?}\")?;\n        }\n        Ok(())\n    }\n}\n\nimpl Error for Status {\n    fn source(&self) -> Option<&(dyn Error + 'static)> {\n        self.0.source.as_ref().map(|err| (&**err) as _)\n    }\n}\n\n///\n/// Take the `Status` value from `trailers` if it is available, else from `status_code`.\n///\npub(crate) fn infer_grpc_status(\n    trailers: Option<&HeaderMap>,\n    status_code: http::StatusCode,\n) -> Result<(), Option<Status>> {\n    if let Some(trailers) = trailers {\n        if let Some(status) = Status::from_header_map(trailers) {\n            if status.code() == Code::Ok {\n                return Ok(());\n            } else {\n                return Err(status.into());\n            }\n        }\n    }\n    trace!(\"trailers missing grpc-status\");\n    let code = match status_code {\n        // Borrowed from https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md\n        http::StatusCode::BAD_REQUEST => Code::Internal,\n        http::StatusCode::UNAUTHORIZED => Code::Unauthenticated,\n        http::StatusCode::FORBIDDEN => Code::PermissionDenied,\n        http::StatusCode::NOT_FOUND => Code::Unimplemented,\n        http::StatusCode::TOO_MANY_REQUESTS\n        | http::StatusCode::BAD_GATEWAY\n        | http::StatusCode::SERVICE_UNAVAILABLE\n        | http::StatusCode::GATEWAY_TIMEOUT => Code::Unavailable,\n        // We got a 200 but no trailers, we can infer that this request is finished.\n        //\n        // This can happen when a streaming response sends two Status but\n        // gRPC requires that we end the stream after the first status.\n        //\n        // https://github.com/hyperium/tonic/issues/681\n        http::StatusCode::OK => return Err(None),\n        _ => Code::Unknown,\n    };\n\n    let msg = format!(\n        \"grpc-status header missing, mapped from HTTP status code {}\",\n        status_code.as_u16(),\n    );\n    let status = Status::new(code, msg);\n    Err(status.into())\n}\n\n// ===== impl Code =====\n\nimpl Code {\n    /// Get the `Code` that represents the integer, if known.\n    ///\n    /// If not known, returns `Code::Unknown` (surprise!).\n    pub const fn from_i32(i: i32) -> Code {\n        match i {\n            0 => Code::Ok,\n            1 => Code::Cancelled,\n            2 => Code::Unknown,\n            3 => Code::InvalidArgument,\n            4 => Code::DeadlineExceeded,\n            5 => Code::NotFound,\n            6 => Code::AlreadyExists,\n            7 => Code::PermissionDenied,\n            8 => Code::ResourceExhausted,\n            9 => Code::FailedPrecondition,\n            10 => Code::Aborted,\n            11 => Code::OutOfRange,\n            12 => Code::Unimplemented,\n            13 => Code::Internal,\n            14 => Code::Unavailable,\n            15 => Code::DataLoss,\n            16 => Code::Unauthenticated,\n\n            _ => Code::Unknown,\n        }\n    }\n\n    /// Convert the string representation of a `Code` (as stored, for example, in the `grpc-status`\n    /// header in a response) into a `Code`. Returns `Code::Unknown` if the code string is not a\n    /// valid gRPC status code.\n    pub fn from_bytes(bytes: &[u8]) -> Code {\n        match bytes.len() {\n            1 => match bytes[0] {\n                b'0' => Code::Ok,\n                b'1' => Code::Cancelled,\n                b'2' => Code::Unknown,\n                b'3' => Code::InvalidArgument,\n                b'4' => Code::DeadlineExceeded,\n                b'5' => Code::NotFound,\n                b'6' => Code::AlreadyExists,\n                b'7' => Code::PermissionDenied,\n                b'8' => Code::ResourceExhausted,\n                b'9' => Code::FailedPrecondition,\n                _ => Code::parse_err(),\n            },\n            2 => match (bytes[0], bytes[1]) {\n                (b'1', b'0') => Code::Aborted,\n                (b'1', b'1') => Code::OutOfRange,\n                (b'1', b'2') => Code::Unimplemented,\n                (b'1', b'3') => Code::Internal,\n                (b'1', b'4') => Code::Unavailable,\n                (b'1', b'5') => Code::DataLoss,\n                (b'1', b'6') => Code::Unauthenticated,\n                _ => Code::parse_err(),\n            },\n            _ => Code::parse_err(),\n        }\n    }\n\n    fn to_header_value(self) -> HeaderValue {\n        match self {\n            Code::Ok => HeaderValue::from_static(\"0\"),\n            Code::Cancelled => HeaderValue::from_static(\"1\"),\n            Code::Unknown => HeaderValue::from_static(\"2\"),\n            Code::InvalidArgument => HeaderValue::from_static(\"3\"),\n            Code::DeadlineExceeded => HeaderValue::from_static(\"4\"),\n            Code::NotFound => HeaderValue::from_static(\"5\"),\n            Code::AlreadyExists => HeaderValue::from_static(\"6\"),\n            Code::PermissionDenied => HeaderValue::from_static(\"7\"),\n            Code::ResourceExhausted => HeaderValue::from_static(\"8\"),\n            Code::FailedPrecondition => HeaderValue::from_static(\"9\"),\n            Code::Aborted => HeaderValue::from_static(\"10\"),\n            Code::OutOfRange => HeaderValue::from_static(\"11\"),\n            Code::Unimplemented => HeaderValue::from_static(\"12\"),\n            Code::Internal => HeaderValue::from_static(\"13\"),\n            Code::Unavailable => HeaderValue::from_static(\"14\"),\n            Code::DataLoss => HeaderValue::from_static(\"15\"),\n            Code::Unauthenticated => HeaderValue::from_static(\"16\"),\n        }\n    }\n\n    fn parse_err() -> Code {\n        trace!(\"error parsing grpc-status\");\n        Code::Unknown\n    }\n}\n\nimpl From<i32> for Code {\n    fn from(i: i32) -> Self {\n        Code::from_i32(i)\n    }\n}\n\nimpl From<Code> for i32 {\n    #[inline]\n    fn from(code: Code) -> i32 {\n        code as i32\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::BoxError;\n\n    #[derive(Debug)]\n    struct Nested(BoxError);\n\n    impl fmt::Display for Nested {\n        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n            write!(f, \"nested error: {}\", self.0)\n        }\n    }\n\n    impl std::error::Error for Nested {\n        fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {\n            Some(&*self.0)\n        }\n    }\n\n    #[test]\n    fn from_error_status() {\n        let orig = Status::new(Code::OutOfRange, \"weeaboo\");\n        let found = Status::from_error(Box::new(orig));\n\n        assert_eq!(found.code(), Code::OutOfRange);\n        assert_eq!(found.message(), \"weeaboo\");\n    }\n\n    #[test]\n    fn from_error_unknown() {\n        let orig: BoxError = \"peek-a-boo\".into();\n        let found = Status::from_error(orig);\n\n        assert_eq!(found.code(), Code::Unknown);\n        assert_eq!(found.message(), \"peek-a-boo\".to_string());\n    }\n\n    #[test]\n    fn from_error_nested() {\n        let orig = Nested(Box::new(Status::new(Code::OutOfRange, \"weeaboo\")));\n        let found = Status::from_error(Box::new(orig));\n\n        assert_eq!(found.code(), Code::OutOfRange);\n        assert_eq!(found.message(), \"weeaboo\");\n    }\n\n    #[test]\n    #[cfg(feature = \"server\")]\n    fn from_error_h2() {\n        use std::error::Error as _;\n\n        let orig = h2::Error::from(h2::Reason::CANCEL);\n        let found = Status::from_error(Box::new(orig));\n\n        assert_eq!(found.code(), Code::Cancelled);\n\n        let source = found\n            .source()\n            .and_then(|err| err.downcast_ref::<h2::Error>())\n            .unwrap();\n        assert_eq!(source.reason(), Some(h2::Reason::CANCEL));\n    }\n\n    #[test]\n    #[cfg(feature = \"server\")]\n    fn to_h2_error() {\n        let orig = Status::new(Code::Cancelled, \"stop eet!\");\n        let err = orig.to_h2_error();\n\n        assert_eq!(err.reason(), Some(h2::Reason::CANCEL));\n    }\n\n    #[test]\n    fn code_from_i32() {\n        // This for loop should catch if we ever add a new variant and don't\n        // update From<i32>.\n        for i in 0..(Code::Unauthenticated as i32) {\n            let code = Code::from(i);\n            assert_eq!(\n                i, code as i32,\n                \"Code::from({}) returned {:?} which is {}\",\n                i, code, code as i32,\n            );\n        }\n\n        assert_eq!(Code::from(-1), Code::Unknown);\n    }\n\n    #[test]\n    fn constructors() {\n        assert_eq!(Status::ok(\"\").code(), Code::Ok);\n        assert_eq!(Status::cancelled(\"\").code(), Code::Cancelled);\n        assert_eq!(Status::unknown(\"\").code(), Code::Unknown);\n        assert_eq!(Status::invalid_argument(\"\").code(), Code::InvalidArgument);\n        assert_eq!(Status::deadline_exceeded(\"\").code(), Code::DeadlineExceeded);\n        assert_eq!(Status::not_found(\"\").code(), Code::NotFound);\n        assert_eq!(Status::already_exists(\"\").code(), Code::AlreadyExists);\n        assert_eq!(Status::permission_denied(\"\").code(), Code::PermissionDenied);\n        assert_eq!(\n            Status::resource_exhausted(\"\").code(),\n            Code::ResourceExhausted\n        );\n        assert_eq!(\n            Status::failed_precondition(\"\").code(),\n            Code::FailedPrecondition\n        );\n        assert_eq!(Status::aborted(\"\").code(), Code::Aborted);\n        assert_eq!(Status::out_of_range(\"\").code(), Code::OutOfRange);\n        assert_eq!(Status::unimplemented(\"\").code(), Code::Unimplemented);\n        assert_eq!(Status::internal(\"\").code(), Code::Internal);\n        assert_eq!(Status::unavailable(\"\").code(), Code::Unavailable);\n        assert_eq!(Status::data_loss(\"\").code(), Code::DataLoss);\n        assert_eq!(Status::unauthenticated(\"\").code(), Code::Unauthenticated);\n    }\n\n    #[test]\n    fn details() {\n        const DETAILS: &[u8] = &[0, 2, 3];\n\n        let status = Status::with_details(Code::Unavailable, \"some message\", DETAILS.into());\n\n        assert_eq!(status.details(), DETAILS);\n\n        let header_map = status.to_header_map().unwrap();\n\n        let b64_details = crate::util::base64::STANDARD_NO_PAD.encode(DETAILS);\n\n        assert_eq!(header_map[Status::GRPC_STATUS_DETAILS], b64_details);\n\n        let status = Status::from_header_map(&header_map).unwrap();\n\n        assert_eq!(status.details(), DETAILS);\n    }\n}\n\n/// Error returned if a request didn't complete within the configured timeout.\n///\n/// Timeouts can be configured either with [`Endpoint::timeout`], [`Server::timeout`], or by\n/// setting the [`grpc-timeout` metadata value][spec].\n///\n/// [`Endpoint::timeout`]: crate::transport::channel::Endpoint::timeout\n/// [`Server::timeout`]: crate::transport::server::Server::timeout\n/// [spec]: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md\n#[derive(Debug)]\npub struct TimeoutExpired(pub ());\n\nimpl fmt::Display for TimeoutExpired {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Timeout expired\")\n    }\n}\n\n// std::error::Error only requires a type to impl Debug and Display\nimpl std::error::Error for TimeoutExpired {}\n\n/// Wrapper type to indicate that an error occurs during the connection\n/// process, so that the appropriate gRPC Status can be inferred.\n#[derive(Debug)]\npub struct ConnectError(pub Box<dyn std::error::Error + Send + Sync>);\n\nimpl fmt::Display for ConnectError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Display::fmt(&self.0, f)\n    }\n}\n\nimpl std::error::Error for ConnectError {\n    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {\n        Some(self.0.as_ref())\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/endpoint.rs",
    "content": "use super::Channel;\n#[cfg(feature = \"_tls-any\")]\nuse super::ClientTlsConfig;\n#[cfg(feature = \"_tls-any\")]\nuse super::service::TlsConnector;\nuse super::service::{self, Executor, SharedExec};\nuse super::uds_connector::UdsConnector;\nuse crate::transport::Error;\n#[cfg(feature = \"_tls-any\")]\nuse crate::transport::error;\nuse bytes::Bytes;\nuse http::{HeaderValue, uri::Uri};\nuse hyper::rt;\nuse hyper_util::client::legacy::connect::HttpConnector;\nuse std::{fmt, future::Future, net::IpAddr, pin::Pin, str, str::FromStr, time::Duration};\nuse tower_service::Service;\n\n#[derive(Clone, PartialEq, Eq, Hash)]\npub(crate) enum EndpointType {\n    Uri(Uri),\n    Uds(String),\n}\n\n/// Channel builder.\n///\n/// This struct is used to build and configure HTTP/2 channels.\n#[derive(Clone)]\npub struct Endpoint {\n    pub(crate) uri: EndpointType,\n    fallback_uri: Uri,\n    pub(crate) origin: Option<Uri>,\n    pub(crate) user_agent: Option<HeaderValue>,\n    pub(crate) timeout: Option<Duration>,\n    pub(crate) concurrency_limit: Option<usize>,\n    pub(crate) rate_limit: Option<(u64, Duration)>,\n    #[cfg(feature = \"_tls-any\")]\n    pub(crate) tls: Option<TlsConnector>,\n    pub(crate) buffer_size: Option<usize>,\n    pub(crate) init_stream_window_size: Option<u32>,\n    pub(crate) init_connection_window_size: Option<u32>,\n    pub(crate) tcp_keepalive: Option<Duration>,\n    pub(crate) tcp_keepalive_interval: Option<Duration>,\n    pub(crate) tcp_keepalive_retries: Option<u32>,\n    pub(crate) tcp_nodelay: bool,\n    pub(crate) http2_keep_alive_interval: Option<Duration>,\n    pub(crate) http2_keep_alive_timeout: Option<Duration>,\n    pub(crate) http2_keep_alive_while_idle: Option<bool>,\n    pub(crate) http2_max_header_list_size: Option<u32>,\n    pub(crate) connect_timeout: Option<Duration>,\n    pub(crate) http2_adaptive_window: Option<bool>,\n    pub(crate) local_address: Option<IpAddr>,\n    pub(crate) executor: SharedExec,\n}\n\nimpl Endpoint {\n    // FIXME: determine if we want to expose this or not. This is really\n    // just used in codegen for a shortcut.\n    #[doc(hidden)]\n    pub fn new<D>(dst: D) -> Result<Self, Error>\n    where\n        D: TryInto<Self>,\n        D::Error: Into<crate::BoxError>,\n    {\n        let me = dst.try_into().map_err(|e| Error::from_source(e.into()))?;\n        #[cfg(feature = \"_tls-any\")]\n        if let EndpointType::Uri(uri) = &me.uri {\n            if me.tls.is_none() && uri.scheme() == Some(&http::uri::Scheme::HTTPS) {\n                return me.tls_config(ClientTlsConfig::new().with_enabled_roots());\n            }\n        }\n        Ok(me)\n    }\n\n    fn new_uri(uri: Uri) -> Self {\n        Self {\n            uri: EndpointType::Uri(uri.clone()),\n            fallback_uri: uri,\n            origin: None,\n            user_agent: None,\n            concurrency_limit: None,\n            rate_limit: None,\n            timeout: None,\n            #[cfg(feature = \"_tls-any\")]\n            tls: None,\n            buffer_size: None,\n            init_stream_window_size: None,\n            init_connection_window_size: None,\n            tcp_keepalive: None,\n            tcp_keepalive_interval: None,\n            tcp_keepalive_retries: None,\n            tcp_nodelay: true,\n            http2_keep_alive_interval: None,\n            http2_keep_alive_timeout: None,\n            http2_keep_alive_while_idle: None,\n            http2_max_header_list_size: None,\n            connect_timeout: None,\n            http2_adaptive_window: None,\n            executor: SharedExec::tokio(),\n            local_address: None,\n        }\n    }\n\n    fn new_uds(uds_filepath: &str) -> Self {\n        Self {\n            uri: EndpointType::Uds(uds_filepath.to_string()),\n            fallback_uri: Uri::from_static(\"http://tonic\"),\n            origin: None,\n            user_agent: None,\n            concurrency_limit: None,\n            rate_limit: None,\n            timeout: None,\n            #[cfg(feature = \"_tls-any\")]\n            tls: None,\n            buffer_size: None,\n            init_stream_window_size: None,\n            init_connection_window_size: None,\n            tcp_keepalive: None,\n            tcp_keepalive_interval: None,\n            tcp_keepalive_retries: None,\n            tcp_nodelay: true,\n            http2_keep_alive_interval: None,\n            http2_keep_alive_timeout: None,\n            http2_keep_alive_while_idle: None,\n            http2_max_header_list_size: None,\n            connect_timeout: None,\n            http2_adaptive_window: None,\n            executor: SharedExec::tokio(),\n            local_address: None,\n        }\n    }\n\n    /// Convert an `Endpoint` from a static string.\n    ///\n    /// # Panics\n    ///\n    /// This function panics if the argument is an invalid URI.\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// Endpoint::from_static(\"https://example.com\");\n    /// ```\n    pub fn from_static(s: &'static str) -> Self {\n        if s.starts_with(\"unix:\") {\n            let uds_filepath = s\n                .strip_prefix(\"unix://\")\n                .or_else(|| s.strip_prefix(\"unix:\"))\n                .expect(\"Invalid unix domain socket URI\");\n            Self::new_uds(uds_filepath)\n        } else {\n            let uri = Uri::from_static(s);\n            Self::new_uri(uri)\n        }\n    }\n\n    /// Convert an `Endpoint` from shared bytes.\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// Endpoint::from_shared(\"https://example.com\".to_string());\n    /// ```\n    pub fn from_shared(s: impl Into<Bytes>) -> Result<Self, Error> {\n        let s = str::from_utf8(&s.into())\n            .map_err(|e| Error::new_invalid_uri().with(e))?\n            .to_string();\n        if s.starts_with(\"unix:\") {\n            let uds_filepath = s\n                .strip_prefix(\"unix://\")\n                .or_else(|| s.strip_prefix(\"unix:\"))\n                .ok_or(Error::new_invalid_uri())?;\n            Ok(Self::new_uds(uds_filepath))\n        } else {\n            let uri = Uri::from_maybe_shared(s).map_err(|e| Error::new_invalid_uri().with(e))?;\n            Ok(Self::from(uri))\n        }\n    }\n\n    /// Set a custom user-agent header.\n    ///\n    /// `user_agent` will be prepended to Tonic's default user-agent string (`tonic/x.x.x`).\n    /// It must be a value that can be converted into a valid  `http::HeaderValue` or building\n    /// the endpoint will fail.\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// # let mut builder = Endpoint::from_static(\"https://example.com\");\n    /// builder.user_agent(\"Greeter\").expect(\"Greeter should be a valid header value\");\n    /// // user-agent: \"Greeter tonic/x.x.x\"\n    /// ```\n    pub fn user_agent<T>(self, user_agent: T) -> Result<Self, Error>\n    where\n        T: TryInto<HeaderValue>,\n    {\n        user_agent\n            .try_into()\n            .map(|ua| Endpoint {\n                user_agent: Some(ua),\n                ..self\n            })\n            .map_err(|_| Error::new_invalid_user_agent())\n    }\n\n    /// Set a custom origin.\n    ///\n    /// Override the `origin`, mainly useful when you are reaching a Server/LoadBalancer\n    /// which serves multiple services at the same time.\n    /// It will play the role of SNI (Server Name Indication).\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// # let mut builder = Endpoint::from_static(\"https://proxy.com\");\n    /// builder.origin(\"https://example.com\".parse().expect(\"http://example.com must be a valid URI\"));\n    /// // origin: \"https://example.com\"\n    /// ```\n    pub fn origin(self, origin: Uri) -> Self {\n        Endpoint {\n            origin: Some(origin),\n            ..self\n        }\n    }\n\n    /// Apply a timeout to each request.\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// # use std::time::Duration;\n    /// # let mut builder = Endpoint::from_static(\"https://example.com\");\n    /// builder.timeout(Duration::from_secs(5));\n    /// ```\n    ///\n    /// # Notes\n    ///\n    /// This does **not** set the timeout metadata (`grpc-timeout` header) on\n    /// the request, meaning the server will not be informed of this timeout,\n    /// for that use [`Request::set_timeout`].\n    ///\n    /// [`Request::set_timeout`]: crate::Request::set_timeout\n    pub fn timeout(self, dur: Duration) -> Self {\n        Endpoint {\n            timeout: Some(dur),\n            ..self\n        }\n    }\n\n    /// Apply a timeout to connecting to the uri.\n    ///\n    /// Defaults to no timeout.\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// # use std::time::Duration;\n    /// # let mut builder = Endpoint::from_static(\"https://example.com\");\n    /// builder.connect_timeout(Duration::from_secs(5));\n    /// ```\n    pub fn connect_timeout(self, dur: Duration) -> Self {\n        Endpoint {\n            connect_timeout: Some(dur),\n            ..self\n        }\n    }\n\n    /// Set whether TCP keepalive messages are enabled on accepted connections.\n    ///\n    /// If `None` is specified, keepalive is disabled, otherwise the duration\n    /// specified will be the time to remain idle before sending TCP keepalive\n    /// probes.\n    ///\n    /// Default is no keepalive (`None`)\n    pub fn tcp_keepalive(self, tcp_keepalive: Option<Duration>) -> Self {\n        Endpoint {\n            tcp_keepalive,\n            ..self\n        }\n    }\n\n    /// Set the duration between two successive TCP keepalive retransmissions,\n    /// if acknowledgement to the previous keepalive transmission is not received.\n    ///\n    /// This is only used if `tcp_keepalive` is not None.\n    ///\n    /// Defaults to None, which is the system default.\n    pub fn tcp_keepalive_interval(self, tcp_keepalive_interval: Option<Duration>) -> Self {\n        Endpoint {\n            tcp_keepalive_interval,\n            ..self\n        }\n    }\n\n    /// Set the number of retransmissions to be carried out before declaring that remote end is not available.\n    ///\n    /// This is only used if `tcp_keepalive` is not None.\n    ///\n    /// Defaults to None, which is the system default.\n    pub fn tcp_keepalive_retries(self, tcp_keepalive_retries: Option<u32>) -> Self {\n        Endpoint {\n            tcp_keepalive_retries,\n            ..self\n        }\n    }\n\n    /// Apply a concurrency limit to each request.\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// # let mut builder = Endpoint::from_static(\"https://example.com\");\n    /// builder.concurrency_limit(256);\n    /// ```\n    pub fn concurrency_limit(self, limit: usize) -> Self {\n        Endpoint {\n            concurrency_limit: Some(limit),\n            ..self\n        }\n    }\n\n    /// Apply a rate limit to each request.\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// # use std::time::Duration;\n    /// # let mut builder = Endpoint::from_static(\"https://example.com\");\n    /// builder.rate_limit(32, Duration::from_secs(1));\n    /// ```\n    pub fn rate_limit(self, limit: u64, duration: Duration) -> Self {\n        Endpoint {\n            rate_limit: Some((limit, duration)),\n            ..self\n        }\n    }\n\n    /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2\n    /// stream-level flow control.\n    ///\n    /// Default is 65,535\n    ///\n    /// [spec]: https://httpwg.org/specs/rfc9113.html#InitialWindowSize\n    pub fn initial_stream_window_size(self, sz: impl Into<Option<u32>>) -> Self {\n        Endpoint {\n            init_stream_window_size: sz.into(),\n            ..self\n        }\n    }\n\n    /// Sets the max connection-level flow control for HTTP2\n    ///\n    /// Default is 65,535\n    pub fn initial_connection_window_size(self, sz: impl Into<Option<u32>>) -> Self {\n        Endpoint {\n            init_connection_window_size: sz.into(),\n            ..self\n        }\n    }\n\n    /// Sets the tower service default internal buffer size\n    ///\n    /// Default is 1024\n    pub fn buffer_size(self, sz: impl Into<Option<usize>>) -> Self {\n        Endpoint {\n            buffer_size: sz.into(),\n            ..self\n        }\n    }\n\n    /// Configures TLS for the endpoint.\n    #[cfg(feature = \"_tls-any\")]\n    pub fn tls_config(self, tls_config: ClientTlsConfig) -> Result<Self, Error> {\n        match &self.uri {\n            EndpointType::Uri(uri) => Ok(Endpoint {\n                tls: Some(\n                    tls_config\n                        .into_tls_connector(uri)\n                        .map_err(Error::from_source)?,\n                ),\n                ..self\n            }),\n            EndpointType::Uds(_) => Err(Error::new(error::Kind::InvalidTlsConfigForUds)),\n        }\n    }\n\n    /// Set the value of `TCP_NODELAY` option for accepted connections. Enabled by default.\n    pub fn tcp_nodelay(self, enabled: bool) -> Self {\n        Endpoint {\n            tcp_nodelay: enabled,\n            ..self\n        }\n    }\n\n    /// Set http2 KEEP_ALIVE_INTERVAL. Uses `hyper`'s default otherwise.\n    pub fn http2_keep_alive_interval(self, interval: Duration) -> Self {\n        Endpoint {\n            http2_keep_alive_interval: Some(interval),\n            ..self\n        }\n    }\n\n    /// Set http2 KEEP_ALIVE_TIMEOUT. Uses `hyper`'s default otherwise.\n    pub fn keep_alive_timeout(self, duration: Duration) -> Self {\n        Endpoint {\n            http2_keep_alive_timeout: Some(duration),\n            ..self\n        }\n    }\n\n    /// Set http2 KEEP_ALIVE_WHILE_IDLE. Uses `hyper`'s default otherwise.\n    pub fn keep_alive_while_idle(self, enabled: bool) -> Self {\n        Endpoint {\n            http2_keep_alive_while_idle: Some(enabled),\n            ..self\n        }\n    }\n\n    /// Sets whether to use an adaptive flow control. Uses `hyper`'s default otherwise.\n    pub fn http2_adaptive_window(self, enabled: bool) -> Self {\n        Endpoint {\n            http2_adaptive_window: Some(enabled),\n            ..self\n        }\n    }\n\n    /// Sets the max size of received header frames.\n    ///\n    /// This will default to whatever the default in hyper is. As of v1.4.1, it is 16 KiB.\n    pub fn http2_max_header_list_size(self, size: u32) -> Self {\n        Endpoint {\n            http2_max_header_list_size: Some(size),\n            ..self\n        }\n    }\n\n    /// Sets the executor used to spawn async tasks.\n    ///\n    /// Uses `tokio::spawn` by default.\n    pub fn executor<E>(mut self, executor: E) -> Self\n    where\n        E: Executor<Pin<Box<dyn Future<Output = ()> + Send>>> + Send + Sync + 'static,\n    {\n        self.executor = SharedExec::new(executor);\n        self\n    }\n\n    pub(crate) fn connector<C>(&self, c: C) -> service::Connector<C> {\n        service::Connector::new(\n            c,\n            #[cfg(feature = \"_tls-any\")]\n            self.tls.clone(),\n        )\n    }\n\n    /// Set the local address.\n    ///\n    /// This sets the IP address the client will use. By default we let hyper select the IP address.\n    pub fn local_address(self, addr: Option<IpAddr>) -> Self {\n        Endpoint {\n            local_address: addr,\n            ..self\n        }\n    }\n\n    pub(crate) fn http_connector(&self) -> service::Connector<HttpConnector> {\n        let mut http = HttpConnector::new();\n        http.enforce_http(false);\n        http.set_nodelay(self.tcp_nodelay);\n        http.set_keepalive(self.tcp_keepalive);\n        http.set_keepalive_interval(self.tcp_keepalive_interval);\n        http.set_keepalive_retries(self.tcp_keepalive_retries);\n        http.set_connect_timeout(self.connect_timeout);\n        http.set_local_address(self.local_address);\n        self.connector(http)\n    }\n\n    pub(crate) fn uds_connector(&self, uds_filepath: &str) -> service::Connector<UdsConnector> {\n        self.connector(UdsConnector::new(uds_filepath))\n    }\n\n    /// Create a channel from this config.\n    pub async fn connect(&self) -> Result<Channel, Error> {\n        match &self.uri {\n            EndpointType::Uri(_) => Channel::connect(self.http_connector(), self.clone()).await,\n            EndpointType::Uds(uds_filepath) => {\n                Channel::connect(self.uds_connector(uds_filepath.as_str()), self.clone()).await\n            }\n        }\n    }\n\n    /// Create a channel from this config.\n    ///\n    /// The channel returned by this method does not attempt to connect to the endpoint until first\n    /// use.\n    pub fn connect_lazy(&self) -> Channel {\n        match &self.uri {\n            EndpointType::Uri(_) => Channel::new(self.http_connector(), self.clone()),\n            EndpointType::Uds(uds_filepath) => {\n                Channel::new(self.uds_connector(uds_filepath.as_str()), self.clone())\n            }\n        }\n    }\n\n    /// Connect with a custom connector.\n    ///\n    /// This allows you to build a [Channel](struct.Channel.html) that uses a non-HTTP transport.\n    /// See the `uds` example for an example on how to use this function to build channel that\n    /// uses a Unix socket transport.\n    ///\n    /// The [`connect_timeout`](Endpoint::connect_timeout) will still be applied.\n    pub async fn connect_with_connector<C>(&self, connector: C) -> Result<Channel, Error>\n    where\n        C: Service<Uri> + Send + 'static,\n        C::Response: rt::Read + rt::Write + Send + Unpin,\n        C::Future: Send,\n        crate::BoxError: From<C::Error> + Send,\n    {\n        let connector = self.connector(connector);\n\n        if let Some(connect_timeout) = self.connect_timeout {\n            let mut connector = hyper_timeout::TimeoutConnector::new(connector);\n            connector.set_connect_timeout(Some(connect_timeout));\n            Channel::connect(connector, self.clone()).await\n        } else {\n            Channel::connect(connector, self.clone()).await\n        }\n    }\n\n    /// Connect with a custom connector lazily.\n    ///\n    /// This allows you to build a [Channel](struct.Channel.html) that uses a non-HTTP transport\n    /// connect to it lazily.\n    ///\n    /// See the `uds` example for an example on how to use this function to build channel that\n    /// uses a Unix socket transport.\n    pub fn connect_with_connector_lazy<C>(&self, connector: C) -> Channel\n    where\n        C: Service<Uri> + Send + 'static,\n        C::Response: rt::Read + rt::Write + Send + Unpin,\n        C::Future: Send,\n        crate::BoxError: From<C::Error> + Send,\n    {\n        let connector = self.connector(connector);\n        if let Some(connect_timeout) = self.connect_timeout {\n            let mut connector = hyper_timeout::TimeoutConnector::new(connector);\n            connector.set_connect_timeout(Some(connect_timeout));\n            Channel::new(connector, self.clone())\n        } else {\n            Channel::new(connector, self.clone())\n        }\n    }\n\n    /// Get the endpoint uri.\n    ///\n    /// ```\n    /// # use tonic::transport::Endpoint;\n    /// # use http::Uri;\n    /// let endpoint = Endpoint::from_static(\"https://example.com\");\n    ///\n    /// assert_eq!(endpoint.uri(), &Uri::from_static(\"https://example.com\"));\n    /// ```\n    pub fn uri(&self) -> &Uri {\n        match &self.uri {\n            EndpointType::Uri(uri) => uri,\n            EndpointType::Uds(_) => &self.fallback_uri,\n        }\n    }\n\n    /// Get the value of `TCP_NODELAY` option for accepted connections.\n    pub fn get_tcp_nodelay(&self) -> bool {\n        self.tcp_nodelay\n    }\n\n    /// Get the connect timeout.\n    pub fn get_connect_timeout(&self) -> Option<Duration> {\n        self.connect_timeout\n    }\n\n    /// Get whether TCP keepalive messages are enabled on accepted connections.\n    ///\n    /// If `None` is specified, keepalive is disabled, otherwise the duration\n    /// specified will be the time to remain idle before sending TCP keepalive\n    /// probes.\n    pub fn get_tcp_keepalive(&self) -> Option<Duration> {\n        self.tcp_keepalive\n    }\n\n    /// Get whether TCP keepalive interval.\n    pub fn get_tcp_keepalive_interval(&self) -> Option<Duration> {\n        self.tcp_keepalive_interval\n    }\n\n    /// Get whether TCP keepalive retries.\n    pub fn get_tcp_keepalive_retries(&self) -> Option<u32> {\n        self.tcp_keepalive_retries\n    }\n}\n\nimpl From<Uri> for Endpoint {\n    fn from(uri: Uri) -> Self {\n        Self::new_uri(uri)\n    }\n}\n\nimpl TryFrom<Bytes> for Endpoint {\n    type Error = Error;\n\n    fn try_from(t: Bytes) -> Result<Self, Self::Error> {\n        Self::from_shared(t)\n    }\n}\n\nimpl TryFrom<String> for Endpoint {\n    type Error = Error;\n\n    fn try_from(t: String) -> Result<Self, Self::Error> {\n        Self::from_shared(t.into_bytes())\n    }\n}\n\nimpl TryFrom<&'static str> for Endpoint {\n    type Error = Error;\n\n    fn try_from(t: &'static str) -> Result<Self, Self::Error> {\n        Self::from_shared(t.as_bytes())\n    }\n}\n\nimpl fmt::Debug for Endpoint {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Endpoint\").finish()\n    }\n}\n\nimpl FromStr for Endpoint {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Self::try_from(s.to_string())\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/mod.rs",
    "content": "//! Client implementation and builder.\n\nmod endpoint;\npub(crate) mod service;\n#[cfg(feature = \"_tls-any\")]\nmod tls;\nmod uds_connector;\n\npub use self::service::Change;\npub use endpoint::Endpoint;\n#[cfg(feature = \"_tls-any\")]\npub use tls::ClientTlsConfig;\n\nuse self::service::{Connection, DynamicServiceStream, Executor, SharedExec};\nuse crate::body::Body;\nuse bytes::Bytes;\nuse http::{\n    Request, Response,\n    uri::{InvalidUri, Uri},\n};\nuse std::{\n    fmt,\n    future::Future,\n    hash::Hash,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tokio::sync::mpsc::{Sender, channel};\n\nuse hyper::rt;\nuse tower::balance::p2c::Balance;\nuse tower::{\n    Service,\n    buffer::{Buffer, future::ResponseFuture as BufferResponseFuture},\n    discover::Discover,\n    util::BoxService,\n};\n\ntype BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;\n\nconst DEFAULT_BUFFER_SIZE: usize = 1024;\n\n/// A default batteries included `transport` channel.\n///\n/// This provides a fully featured http2 gRPC client based on `hyper`\n/// and `tower` services.\n///\n/// # Multiplexing requests\n///\n/// Sending a request on a channel requires a `&mut self` and thus can only send\n/// one request in flight. This is intentional and is required to follow the `Service`\n/// contract from the `tower` library which this channel implementation is built on\n/// top of.\n///\n/// `tower` itself has a concept of `poll_ready` which is the main mechanism to apply\n/// back pressure. `poll_ready` takes a `&mut self` and when it returns `Poll::Ready`\n/// we know the `Service` is able to accept only one request before we must `poll_ready`\n/// again. Due to this fact any `async fn` that wants to poll for readiness and submit\n/// the request must have a `&mut self` reference.\n///\n/// To work around this and to ease the use of the channel, `Channel` provides a\n/// `Clone` implementation that is _cheap_. This is because at the very top level\n/// the channel is backed by a `tower_buffer::Buffer` which runs the connection\n/// in a background task and provides a `mpsc` channel interface. Due to this\n/// cloning the `Channel` type is cheap and encouraged.\n#[derive(Clone)]\npub struct Channel {\n    svc: Buffer<Request<Body>, BoxFuture<'static, Result<Response<Body>, crate::BoxError>>>,\n}\n\n/// A future that resolves to an HTTP response.\n///\n/// This is returned by the `Service::call` on [`Channel`].\npub struct ResponseFuture {\n    inner: BufferResponseFuture<BoxFuture<'static, Result<Response<Body>, crate::BoxError>>>,\n}\n\nimpl Channel {\n    /// Create an [`Endpoint`] builder that can create [`Channel`]s.\n    pub fn builder(uri: Uri) -> Endpoint {\n        Endpoint::from(uri)\n    }\n\n    /// Create an [`Endpoint`] from a static string.\n    ///\n    /// ```\n    /// # use tonic::transport::Channel;\n    /// Channel::from_static(\"https://example.com\");\n    /// ```\n    pub fn from_static(s: &'static str) -> Endpoint {\n        let uri = Uri::from_static(s);\n        Self::builder(uri)\n    }\n\n    /// Create an [`Endpoint`] from shared bytes.\n    ///\n    /// ```\n    /// # use tonic::transport::Channel;\n    /// Channel::from_shared(\"https://example.com\");\n    /// ```\n    pub fn from_shared(s: impl Into<Bytes>) -> Result<Endpoint, InvalidUri> {\n        let uri = Uri::from_maybe_shared(s.into())?;\n        Ok(Self::builder(uri))\n    }\n\n    /// Balance a list of [`Endpoint`]'s.\n    ///\n    /// This creates a [`Channel`] that will load balance across all the\n    /// provided endpoints.\n    pub fn balance_list(list: impl Iterator<Item = Endpoint>) -> Self {\n        let (channel, tx) = Self::balance_channel(DEFAULT_BUFFER_SIZE);\n        list.for_each(|endpoint| {\n            tx.try_send(Change::Insert(endpoint.uri.clone(), endpoint))\n                .unwrap();\n        });\n\n        channel\n    }\n\n    /// Balance a list of [`Endpoint`]'s.\n    ///\n    /// This creates a [`Channel`] that will listen to a stream of change events and will add or remove provided endpoints.\n    pub fn balance_channel<K>(capacity: usize) -> (Self, Sender<Change<K, Endpoint>>)\n    where\n        K: Hash + Eq + Send + Clone + 'static,\n    {\n        Self::balance_channel_with_executor(capacity, SharedExec::tokio())\n    }\n\n    /// Balance a list of [`Endpoint`]'s.\n    ///\n    /// This creates a [`Channel`] that will listen to a stream of change events and will add or remove provided endpoints.\n    ///\n    /// The [`Channel`] will use the given executor to spawn async tasks.\n    pub fn balance_channel_with_executor<K, E>(\n        capacity: usize,\n        executor: E,\n    ) -> (Self, Sender<Change<K, Endpoint>>)\n    where\n        K: Hash + Eq + Send + Clone + 'static,\n        E: Executor<Pin<Box<dyn Future<Output = ()> + Send>>> + Send + Sync + 'static,\n    {\n        let (tx, rx) = channel(capacity);\n        let list = DynamicServiceStream::new(rx);\n        (Self::balance(list, DEFAULT_BUFFER_SIZE, executor), tx)\n    }\n\n    /// Create a new [`Channel`] using a custom connector to the provided [Endpoint].\n    ///\n    /// This is a lower level API, prefer to use [`Endpoint::connect_lazy`] if you are not using a custom connector.\n    pub fn new<C>(connector: C, endpoint: Endpoint) -> Self\n    where\n        C: Service<Uri> + Send + 'static,\n        C::Error: Into<crate::BoxError> + Send,\n        C::Future: Send,\n        C::Response: rt::Read + rt::Write + Unpin + Send + 'static,\n    {\n        let buffer_size = endpoint.buffer_size.unwrap_or(DEFAULT_BUFFER_SIZE);\n        let executor = endpoint.executor.clone();\n\n        let svc = Connection::lazy(connector, endpoint);\n        let (svc, worker) = Buffer::pair(svc, buffer_size);\n\n        executor.execute(worker);\n\n        Channel { svc }\n    }\n\n    /// Connect to the provided [`Endpoint`] using the provided connector, and return a new [`Channel`].\n    ///\n    /// This is a lower level API, prefer to use [`Endpoint::connect`] if you are not using a custom connector.\n    pub async fn connect<C>(connector: C, endpoint: Endpoint) -> Result<Self, super::Error>\n    where\n        C: Service<Uri> + Send + 'static,\n        C::Error: Into<crate::BoxError> + Send,\n        C::Future: Unpin + Send,\n        C::Response: rt::Read + rt::Write + Unpin + Send + 'static,\n    {\n        let buffer_size = endpoint.buffer_size.unwrap_or(DEFAULT_BUFFER_SIZE);\n        let executor = endpoint.executor.clone();\n\n        let svc = Connection::connect(connector, endpoint)\n            .await\n            .map_err(super::Error::from_source)?;\n        let (svc, worker) = Buffer::pair(svc, buffer_size);\n        executor.execute(worker);\n\n        Ok(Channel { svc })\n    }\n\n    pub(crate) fn balance<D, E>(discover: D, buffer_size: usize, executor: E) -> Self\n    where\n        D: Discover<Service = Connection> + Unpin + Send + 'static,\n        D::Error: Into<crate::BoxError>,\n        D::Key: Hash + Send + Clone,\n        E: Executor<BoxFuture<'static, ()>> + Send + Sync + 'static,\n    {\n        let svc = Balance::new(discover);\n\n        let svc = BoxService::new(svc);\n        let (svc, worker) = Buffer::pair(svc, buffer_size);\n        executor.execute(Box::pin(worker));\n\n        Channel { svc }\n    }\n}\n\nimpl Service<http::Request<Body>> for Channel {\n    type Response = http::Response<Body>;\n    type Error = super::Error;\n    type Future = ResponseFuture;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Service::poll_ready(&mut self.svc, cx).map_err(super::Error::from_source)\n    }\n\n    fn call(&mut self, request: http::Request<Body>) -> Self::Future {\n        let inner = Service::call(&mut self.svc, request);\n\n        ResponseFuture { inner }\n    }\n}\n\nimpl Future for ResponseFuture {\n    type Output = Result<Response<Body>, super::Error>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        Pin::new(&mut self.inner)\n            .poll(cx)\n            .map_err(super::Error::from_source)\n    }\n}\n\nimpl fmt::Debug for Channel {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Channel\").finish()\n    }\n}\n\nimpl fmt::Debug for ResponseFuture {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ResponseFuture\").finish()\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/add_origin.rs",
    "content": "use crate::transport::channel::BoxFuture;\nuse http::uri::Authority;\nuse http::uri::Scheme;\nuse http::{Request, Uri};\nuse std::task::{Context, Poll};\nuse tower_service::Service;\n\n#[derive(Debug)]\npub(crate) struct AddOrigin<T> {\n    inner: T,\n    scheme: Option<Scheme>,\n    authority: Option<Authority>,\n}\n\nimpl<T> AddOrigin<T> {\n    pub(crate) fn new(inner: T, origin: Uri) -> Self {\n        let http::uri::Parts {\n            scheme, authority, ..\n        } = origin.into_parts();\n\n        Self {\n            inner,\n            scheme,\n            authority,\n        }\n    }\n}\n\nimpl<T, ReqBody> Service<Request<ReqBody>> for AddOrigin<T>\nwhere\n    T: Service<Request<ReqBody>>,\n    T::Future: Send + 'static,\n    T::Error: Into<crate::BoxError>,\n{\n    type Response = T::Response;\n    type Error = crate::BoxError;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: Request<ReqBody>) -> Self::Future {\n        if self.scheme.is_none() || self.authority.is_none() {\n            let err = crate::transport::Error::new_invalid_uri();\n            return Box::pin(async move { Err::<Self::Response, _>(err.into()) });\n        }\n\n        // Split the request into the head and the body.\n        let (mut head, body) = req.into_parts();\n\n        // Update the request URI\n        head.uri = {\n            // Split the request URI into parts.\n            let mut uri: http::uri::Parts = head.uri.into();\n            // Update the URI parts, setting the scheme and authority\n            uri.scheme = self.scheme.clone();\n            uri.authority = self.authority.clone();\n\n            http::Uri::from_parts(uri).expect(\"valid uri\")\n        };\n\n        let request = Request::from_parts(head, body);\n\n        let fut = self.inner.call(request);\n\n        Box::pin(async move { fut.await.map_err(Into::into) })\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/connection.rs",
    "content": "use super::{AddOrigin, Reconnect, SharedExec, UserAgent};\nuse crate::{\n    body::Body,\n    transport::{Endpoint, channel::BoxFuture, service::GrpcTimeout},\n};\nuse http::{Request, Response, Uri};\nuse hyper::rt;\nuse hyper::{client::conn::http2::Builder, rt::Executor};\nuse hyper_util::rt::TokioTimer;\nuse std::{\n    fmt,\n    task::{Context, Poll},\n};\nuse tower::load::Load;\nuse tower::{\n    ServiceBuilder, ServiceExt,\n    layer::Layer,\n    limit::{concurrency::ConcurrencyLimitLayer, rate::RateLimitLayer},\n    util::BoxService,\n};\nuse tower_service::Service;\n\npub(crate) struct Connection {\n    inner: BoxService<Request<Body>, Response<Body>, crate::BoxError>,\n}\n\nimpl Connection {\n    fn new<C>(connector: C, endpoint: Endpoint, is_lazy: bool) -> Self\n    where\n        C: Service<Uri> + Send + 'static,\n        C::Error: Into<crate::BoxError> + Send,\n        C::Future: Send,\n        C::Response: rt::Read + rt::Write + Unpin + Send + 'static,\n    {\n        let mut settings: Builder<SharedExec> = Builder::new(endpoint.executor.clone())\n            .initial_stream_window_size(endpoint.init_stream_window_size)\n            .initial_connection_window_size(endpoint.init_connection_window_size)\n            .keep_alive_interval(endpoint.http2_keep_alive_interval)\n            .timer(TokioTimer::new())\n            .clone();\n\n        if let Some(val) = endpoint.http2_keep_alive_timeout {\n            settings.keep_alive_timeout(val);\n        }\n\n        if let Some(val) = endpoint.http2_keep_alive_while_idle {\n            settings.keep_alive_while_idle(val);\n        }\n\n        if let Some(val) = endpoint.http2_adaptive_window {\n            settings.adaptive_window(val);\n        }\n\n        if let Some(val) = endpoint.http2_max_header_list_size {\n            settings.max_header_list_size(val);\n        }\n\n        let stack = ServiceBuilder::new()\n            .layer_fn(|s| {\n                let origin = endpoint.origin.as_ref().unwrap_or(endpoint.uri()).clone();\n\n                AddOrigin::new(s, origin)\n            })\n            .layer_fn(|s| UserAgent::new(s, endpoint.user_agent.clone()))\n            .layer_fn(|s| GrpcTimeout::new(s, endpoint.timeout))\n            .option_layer(endpoint.concurrency_limit.map(ConcurrencyLimitLayer::new))\n            .option_layer(endpoint.rate_limit.map(|(l, d)| RateLimitLayer::new(l, d)))\n            .into_inner();\n\n        let make_service =\n            MakeSendRequestService::new(connector, endpoint.executor.clone(), settings);\n\n        let conn = Reconnect::new(make_service, endpoint.uri().clone(), is_lazy);\n\n        Self {\n            inner: BoxService::new(stack.layer(conn)),\n        }\n    }\n\n    pub(crate) async fn connect<C>(\n        connector: C,\n        endpoint: Endpoint,\n    ) -> Result<Self, crate::BoxError>\n    where\n        C: Service<Uri> + Send + 'static,\n        C::Error: Into<crate::BoxError> + Send,\n        C::Future: Unpin + Send,\n        C::Response: rt::Read + rt::Write + Unpin + Send + 'static,\n    {\n        Self::new(connector, endpoint, false).ready_oneshot().await\n    }\n\n    pub(crate) fn lazy<C>(connector: C, endpoint: Endpoint) -> Self\n    where\n        C: Service<Uri> + Send + 'static,\n        C::Error: Into<crate::BoxError> + Send,\n        C::Future: Send,\n        C::Response: rt::Read + rt::Write + Unpin + Send + 'static,\n    {\n        Self::new(connector, endpoint, true)\n    }\n}\n\nimpl Service<Request<Body>> for Connection {\n    type Response = Response<Body>;\n    type Error = crate::BoxError;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Service::poll_ready(&mut self.inner, cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: Request<Body>) -> Self::Future {\n        self.inner.call(req)\n    }\n}\n\nimpl Load for Connection {\n    type Metric = usize;\n\n    fn load(&self) -> Self::Metric {\n        0\n    }\n}\n\nimpl fmt::Debug for Connection {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Connection\").finish()\n    }\n}\n\nstruct SendRequest {\n    inner: hyper::client::conn::http2::SendRequest<Body>,\n}\n\nimpl From<hyper::client::conn::http2::SendRequest<Body>> for SendRequest {\n    fn from(inner: hyper::client::conn::http2::SendRequest<Body>) -> Self {\n        Self { inner }\n    }\n}\n\nimpl tower::Service<Request<Body>> for SendRequest {\n    type Response = Response<Body>;\n    type Error = crate::BoxError;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: Request<Body>) -> Self::Future {\n        let fut = self.inner.send_request(req);\n\n        Box::pin(async move { fut.await.map_err(Into::into).map(|res| res.map(Body::new)) })\n    }\n}\n\nstruct MakeSendRequestService<C> {\n    connector: C,\n    executor: SharedExec,\n    settings: Builder<SharedExec>,\n}\n\nimpl<C> MakeSendRequestService<C> {\n    fn new(connector: C, executor: SharedExec, settings: Builder<SharedExec>) -> Self {\n        Self {\n            connector,\n            executor,\n            settings,\n        }\n    }\n}\n\nimpl<C> tower::Service<Uri> for MakeSendRequestService<C>\nwhere\n    C: Service<Uri> + Send + 'static,\n    C::Error: Into<crate::BoxError> + Send,\n    C::Future: Send,\n    C::Response: rt::Read + rt::Write + Unpin + Send,\n{\n    type Response = SendRequest;\n    type Error = crate::BoxError;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.connector.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: Uri) -> Self::Future {\n        let fut = self.connector.call(req);\n        let builder = self.settings.clone();\n        let executor = self.executor.clone();\n\n        Box::pin(async move {\n            let io = fut.await.map_err(Into::into)?;\n            let (send_request, conn) = builder.handshake(io).await?;\n\n            Executor::<BoxFuture<'static, ()>>::execute(\n                &executor,\n                Box::pin(async move {\n                    if let Err(e) = conn.await {\n                        tracing::debug!(\"connection task error: {:?}\", e);\n                    }\n                }) as _,\n            );\n\n            Ok(SendRequest::from(send_request))\n        })\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/connector.rs",
    "content": "use super::BoxedIo;\n#[cfg(feature = \"_tls-any\")]\nuse super::TlsConnector;\nuse crate::ConnectError;\nuse crate::transport::channel::BoxFuture;\nuse http::Uri;\n#[cfg(feature = \"_tls-any\")]\nuse std::fmt;\nuse std::task::{Context, Poll};\n\nuse hyper::rt;\n\n#[cfg(feature = \"_tls-any\")]\nuse hyper_util::rt::TokioIo;\nuse tower_service::Service;\n\npub(crate) struct Connector<C> {\n    inner: C,\n    #[cfg(feature = \"_tls-any\")]\n    tls: Option<TlsConnector>,\n}\n\nimpl<C> Connector<C> {\n    pub(crate) fn new(inner: C, #[cfg(feature = \"_tls-any\")] tls: Option<TlsConnector>) -> Self {\n        Self {\n            inner,\n            #[cfg(feature = \"_tls-any\")]\n            tls,\n        }\n    }\n}\n\nimpl<C> Service<Uri> for Connector<C>\nwhere\n    C: Service<Uri>,\n    C::Response: rt::Read + rt::Write + Unpin + Send + 'static,\n    C::Future: Send + 'static,\n    crate::BoxError: From<C::Error> + Send + 'static,\n{\n    type Response = BoxedIo;\n    type Error = ConnectError;\n    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner\n            .poll_ready(cx)\n            .map_err(|err| ConnectError(From::from(err)))\n    }\n\n    fn call(&mut self, uri: Uri) -> Self::Future {\n        #[cfg(feature = \"_tls-any\")]\n        let tls = self.tls.clone();\n\n        #[cfg(feature = \"_tls-any\")]\n        let is_https = uri.scheme_str() == Some(\"https\");\n        let connect = self.inner.call(uri);\n\n        Box::pin(async move {\n            async {\n                let io = connect.await?;\n\n                #[cfg(feature = \"_tls-any\")]\n                if is_https {\n                    return if let Some(tls) = tls {\n                        let io = tls.connect(TokioIo::new(io)).await?;\n                        Ok(io)\n                    } else {\n                        Err(HttpsUriWithoutTlsSupport(()).into())\n                    };\n                }\n\n                Ok::<_, crate::BoxError>(BoxedIo::new(io))\n            }\n            .await\n            .map_err(ConnectError)\n        })\n    }\n}\n\n/// Error returned when trying to connect to an HTTPS endpoint without TLS enabled.\n#[cfg(feature = \"_tls-any\")]\n#[derive(Debug)]\npub(crate) struct HttpsUriWithoutTlsSupport(());\n\n#[cfg(feature = \"_tls-any\")]\nimpl fmt::Display for HttpsUriWithoutTlsSupport {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Connecting to HTTPS without TLS enabled\")\n    }\n}\n\n// std::error::Error only requires a type to impl Debug and Display\n#[cfg(feature = \"_tls-any\")]\nimpl std::error::Error for HttpsUriWithoutTlsSupport {}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/discover.rs",
    "content": "use super::super::{Connection, Endpoint};\n\nuse std::{\n    hash::Hash,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tokio::sync::mpsc::Receiver;\nuse tokio_stream::Stream;\nuse tower::discover::Change as TowerChange;\n\n/// A change in the service set.\n#[derive(Debug, Clone)]\npub enum Change<K, V> {\n    /// A new service identified by key `K` was identified.\n    Insert(K, V),\n    /// The service identified by key `K` disappeared.\n    Remove(K),\n}\n\npub(crate) struct DynamicServiceStream<K: Hash + Eq + Clone> {\n    changes: Receiver<Change<K, Endpoint>>,\n}\n\nimpl<K: Hash + Eq + Clone> DynamicServiceStream<K> {\n    pub(crate) fn new(changes: Receiver<Change<K, Endpoint>>) -> Self {\n        Self { changes }\n    }\n}\n\nimpl<K: Hash + Eq + Clone> Stream for DynamicServiceStream<K> {\n    type Item = Result<TowerChange<K, Connection>, crate::BoxError>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        match Pin::new(&mut self.changes).poll_recv(cx) {\n            Poll::Pending | Poll::Ready(None) => Poll::Pending,\n            Poll::Ready(Some(change)) => match change {\n                Change::Insert(k, endpoint) => {\n                    let connection = Connection::lazy(endpoint.http_connector(), endpoint);\n                    Poll::Ready(Some(Ok(TowerChange::Insert(k, connection))))\n                }\n                Change::Remove(k) => Poll::Ready(Some(Ok(TowerChange::Remove(k)))),\n            },\n        }\n    }\n}\n\nimpl<K: Hash + Eq + Clone> Unpin for DynamicServiceStream<K> {}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/executor.rs",
    "content": "use crate::transport::channel::BoxFuture;\nuse hyper_util::rt::TokioExecutor;\nuse std::{future::Future, sync::Arc};\n\npub(crate) use hyper::rt::Executor;\n\n#[derive(Clone)]\npub(crate) struct SharedExec {\n    inner: Arc<dyn Executor<BoxFuture<'static, ()>> + Send + Sync + 'static>,\n}\n\nimpl SharedExec {\n    pub(crate) fn new<E>(exec: E) -> Self\n    where\n        E: Executor<BoxFuture<'static, ()>> + Send + Sync + 'static,\n    {\n        Self {\n            inner: Arc::new(exec),\n        }\n    }\n\n    pub(crate) fn tokio() -> Self {\n        Self::new(TokioExecutor::new())\n    }\n}\n\nimpl<F> Executor<F> for SharedExec\nwhere\n    F: Future<Output = ()> + Send + 'static,\n{\n    fn execute(&self, fut: F) {\n        self.inner.execute(Box::pin(fut))\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/io.rs",
    "content": "use std::io::{self, IoSlice};\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse hyper::rt;\nuse hyper_util::client::legacy::connect::{Connected as HyperConnected, Connection};\n\npub(in crate::transport) trait Io:\n    rt::Read + rt::Write + Send + 'static\n{\n}\n\nimpl<T> Io for T where T: rt::Read + rt::Write + Send + 'static {}\n\npub(crate) struct BoxedIo(Pin<Box<dyn Io>>);\n\nimpl BoxedIo {\n    pub(in crate::transport) fn new<I: Io>(io: I) -> Self {\n        BoxedIo(Box::pin(io))\n    }\n}\n\nimpl Connection for BoxedIo {\n    fn connected(&self) -> HyperConnected {\n        HyperConnected::new()\n    }\n}\n\nimpl rt::Read for BoxedIo {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: rt::ReadBufCursor<'_>,\n    ) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.0).poll_read(cx, buf)\n    }\n}\n\nimpl rt::Write for BoxedIo {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<io::Result<usize>> {\n        Pin::new(&mut self.0).poll_write(cx, buf)\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.0).poll_flush(cx)\n    }\n\n    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.0).poll_shutdown(cx)\n    }\n\n    fn poll_write_vectored(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[IoSlice<'_>],\n    ) -> Poll<Result<usize, io::Error>> {\n        Pin::new(&mut self.0).poll_write_vectored(cx, bufs)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        self.0.is_write_vectored()\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/mod.rs",
    "content": "mod add_origin;\nuse self::add_origin::AddOrigin;\n\nmod user_agent;\nuse self::user_agent::UserAgent;\n\nmod reconnect;\nuse self::reconnect::Reconnect;\n\nmod connection;\npub(super) use self::connection::Connection;\n\nmod discover;\npub use self::discover::Change;\npub(super) use self::discover::DynamicServiceStream;\n\nmod io;\nuse self::io::BoxedIo;\n\nmod connector;\npub(crate) use self::connector::Connector;\n\nmod executor;\npub(super) use self::executor::{Executor, SharedExec};\n\n#[cfg(feature = \"_tls-any\")]\nmod tls;\n#[cfg(feature = \"_tls-any\")]\npub(super) use self::tls::TlsConnector;\n"
  },
  {
    "path": "tonic/src/transport/channel/service/reconnect.rs",
    "content": "use pin_project::pin_project;\nuse std::fmt;\nuse std::{\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tower::make::MakeService;\nuse tower_service::Service;\nuse tracing::trace;\n\npub(crate) struct Reconnect<M, Target>\nwhere\n    M: Service<Target>,\n    M::Error: Into<crate::BoxError>,\n{\n    mk_service: M,\n    state: State<M::Future, M::Response>,\n    target: Target,\n    error: Option<crate::BoxError>,\n    has_been_connected: bool,\n    is_lazy: bool,\n}\n\n#[derive(Debug)]\nenum State<F, S> {\n    Idle,\n    Connecting(F),\n    Connected(S),\n}\n\nimpl<M, Target> Reconnect<M, Target>\nwhere\n    M: Service<Target>,\n    M::Error: Into<crate::BoxError>,\n{\n    pub(crate) fn new(mk_service: M, target: Target, is_lazy: bool) -> Self {\n        Reconnect {\n            mk_service,\n            state: State::Idle,\n            target,\n            error: None,\n            has_been_connected: false,\n            is_lazy,\n        }\n    }\n}\n\nimpl<M, Target, S, Request> Service<Request> for Reconnect<M, Target>\nwhere\n    M: Service<Target, Response = S>,\n    S: Service<Request>,\n    M::Future: Unpin,\n    crate::BoxError: From<M::Error> + From<S::Error>,\n    Target: Clone,\n    <M as tower_service::Service<Target>>::Error: Into<crate::BoxError>,\n{\n    type Response = S::Response;\n    type Error = crate::BoxError;\n    type Future = ResponseFuture<S::Future>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        let mut state;\n\n        if self.error.is_some() {\n            return Poll::Ready(Ok(()));\n        }\n\n        loop {\n            match self.state {\n                State::Idle => {\n                    trace!(\"poll_ready; idle\");\n                    match self.mk_service.poll_ready(cx) {\n                        Poll::Ready(r) => r?,\n                        Poll::Pending => {\n                            trace!(\"poll_ready; MakeService not ready\");\n                            return Poll::Pending;\n                        }\n                    }\n\n                    let fut = self.mk_service.make_service(self.target.clone());\n                    self.state = State::Connecting(fut);\n                    continue;\n                }\n                State::Connecting(ref mut f) => {\n                    trace!(\"poll_ready; connecting\");\n                    match Pin::new(f).poll(cx) {\n                        Poll::Ready(Ok(service)) => {\n                            state = State::Connected(service);\n                        }\n                        Poll::Pending => {\n                            trace!(\"poll_ready; not ready\");\n                            return Poll::Pending;\n                        }\n                        Poll::Ready(Err(e)) => {\n                            trace!(\"poll_ready; error\");\n\n                            state = State::Idle;\n\n                            if !(self.has_been_connected || self.is_lazy) {\n                                return Poll::Ready(Err(e.into()));\n                            } else {\n                                let error = e.into();\n                                tracing::debug!(\"reconnect::poll_ready: {:?}\", error);\n                                self.error = Some(error);\n                                break;\n                            }\n                        }\n                    }\n                }\n                State::Connected(ref mut inner) => {\n                    trace!(\"poll_ready; connected\");\n\n                    self.has_been_connected = true;\n\n                    match inner.poll_ready(cx) {\n                        Poll::Ready(Ok(())) => {\n                            trace!(\"poll_ready; ready\");\n                            return Poll::Ready(Ok(()));\n                        }\n                        Poll::Pending => {\n                            trace!(\"poll_ready; not ready\");\n                            return Poll::Pending;\n                        }\n                        Poll::Ready(Err(_)) => {\n                            trace!(\"poll_ready; error\");\n                            state = State::Idle;\n                        }\n                    }\n                }\n            }\n\n            self.state = state;\n        }\n\n        self.state = state;\n        Poll::Ready(Ok(()))\n    }\n\n    fn call(&mut self, request: Request) -> Self::Future {\n        tracing::trace!(\"Reconnect::call\");\n        if let Some(error) = self.error.take() {\n            tracing::debug!(\"error: {}\", error);\n            return ResponseFuture::error(error);\n        }\n\n        let State::Connected(service) = &mut self.state else {\n            panic!(\"service not ready; poll_ready must be called first\");\n        };\n\n        let fut = service.call(request);\n        ResponseFuture::new(fut)\n    }\n}\n\nimpl<M, Target> fmt::Debug for Reconnect<M, Target>\nwhere\n    M: Service<Target> + fmt::Debug,\n    M::Future: fmt::Debug,\n    M::Response: fmt::Debug,\n    Target: fmt::Debug,\n    <M as tower_service::Service<Target>>::Error: Into<crate::BoxError>,\n{\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt.debug_struct(\"Reconnect\")\n            .field(\"mk_service\", &self.mk_service)\n            .field(\"state\", &self.state)\n            .field(\"target\", &self.target)\n            .finish()\n    }\n}\n\n/// Future that resolves to the response or failure to connect.\n#[pin_project]\n#[derive(Debug)]\npub(crate) struct ResponseFuture<F> {\n    #[pin]\n    inner: Inner<F>,\n}\n\n#[pin_project(project = InnerProj)]\n#[derive(Debug)]\nenum Inner<F> {\n    Future(#[pin] F),\n    Error(Option<crate::BoxError>),\n}\n\nimpl<F> ResponseFuture<F> {\n    pub(crate) fn new(inner: F) -> Self {\n        ResponseFuture {\n            inner: Inner::Future(inner),\n        }\n    }\n\n    pub(crate) fn error(error: crate::BoxError) -> Self {\n        ResponseFuture {\n            inner: Inner::Error(Some(error)),\n        }\n    }\n}\n\nimpl<F, T, E> Future for ResponseFuture<F>\nwhere\n    F: Future<Output = Result<T, E>>,\n    E: Into<crate::BoxError>,\n{\n    type Output = Result<T, crate::BoxError>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        //self.project().inner.poll(cx).map_err(Into::into)\n        let me = self.project();\n        match me.inner.project() {\n            InnerProj::Future(fut) => fut.poll(cx).map_err(Into::into),\n            InnerProj::Error(e) => {\n                let e = e.take().expect(\"Polled after ready.\");\n                Poll::Ready(Err(e))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/tls.rs",
    "content": "use std::fmt;\nuse std::{sync::Arc, time::Duration};\n\nuse hyper_util::rt::TokioIo;\nuse tokio::io::{AsyncRead, AsyncWrite};\nuse tokio::time;\nuse tokio_rustls::{\n    TlsConnector as RustlsConnector,\n    rustls::{\n        ClientConfig, ConfigBuilder, RootCertStore, WantsVerifier, crypto,\n        pki_types::{ServerName, TrustAnchor},\n    },\n};\n\nuse super::io::BoxedIo;\nuse crate::transport::service::tls::{\n    ALPN_H2, TlsError, convert_certificate_to_pki_types, convert_identity_to_pki_types,\n};\nuse crate::transport::tls::{Certificate, Identity};\n\n#[derive(Clone)]\npub(crate) struct TlsConnector {\n    config: Arc<ClientConfig>,\n    domain: Arc<ServerName<'static>>,\n    assume_http2: bool,\n    timeout: Option<Duration>,\n}\n\nimpl TlsConnector {\n    #[allow(clippy::too_many_arguments)]\n    pub(crate) fn new(\n        ca_certs: Vec<Certificate>,\n        trust_anchors: Vec<TrustAnchor<'static>>,\n        identity: Option<Identity>,\n        domain: &str,\n        assume_http2: bool,\n        use_key_log: bool,\n        timeout: Option<Duration>,\n        #[cfg(feature = \"tls-native-roots\")] with_native_roots: bool,\n        #[cfg(feature = \"tls-webpki-roots\")] with_webpki_roots: bool,\n    ) -> Result<Self, crate::BoxError> {\n        fn with_provider(\n            provider: Arc<crypto::CryptoProvider>,\n        ) -> ConfigBuilder<ClientConfig, WantsVerifier> {\n            ClientConfig::builder_with_provider(provider)\n                .with_safe_default_protocol_versions()\n                .unwrap()\n        }\n\n        #[allow(unreachable_patterns)]\n        let builder = match crypto::CryptoProvider::get_default() {\n            Some(provider) => with_provider(provider.clone()),\n            #[cfg(feature = \"tls-ring\")]\n            None => with_provider(Arc::new(crypto::ring::default_provider())),\n            #[cfg(feature = \"tls-aws-lc\")]\n            None => with_provider(Arc::new(crypto::aws_lc_rs::default_provider())),\n            // somehow tls is enabled, but neither of the crypto features are enabled.\n            _ => ClientConfig::builder(),\n        };\n\n        let mut roots = RootCertStore::from_iter(trust_anchors);\n\n        #[cfg(feature = \"tls-native-roots\")]\n        if with_native_roots {\n            let rustls_native_certs::CertificateResult { certs, errors, .. } =\n                rustls_native_certs::load_native_certs();\n            if !errors.is_empty() {\n                tracing::debug!(\"errors occurred when loading native certs: {errors:?}\");\n            }\n            if certs.is_empty() {\n                return Err(TlsError::NativeCertsNotFound.into());\n            }\n            roots.add_parsable_certificates(certs);\n        }\n\n        #[cfg(feature = \"tls-webpki-roots\")]\n        if with_webpki_roots {\n            roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());\n        }\n\n        for cert in ca_certs {\n            roots.add_parsable_certificates(convert_certificate_to_pki_types(&cert)?);\n        }\n\n        let builder = builder.with_root_certificates(roots);\n        let mut config = match identity {\n            Some(identity) => {\n                let (client_cert, client_key) = convert_identity_to_pki_types(&identity)?;\n                builder.with_client_auth_cert(client_cert, client_key)?\n            }\n            None => builder.with_no_client_auth(),\n        };\n\n        if use_key_log {\n            config.key_log = Arc::new(tokio_rustls::rustls::KeyLogFile::new());\n        }\n\n        config.alpn_protocols.push(ALPN_H2.into());\n        Ok(Self {\n            config: Arc::new(config),\n            domain: Arc::new(ServerName::try_from(domain)?.to_owned()),\n            assume_http2,\n            timeout,\n        })\n    }\n\n    pub(crate) async fn connect<I>(&self, io: I) -> Result<BoxedIo, crate::BoxError>\n    where\n        I: AsyncRead + AsyncWrite + Send + Unpin + 'static,\n    {\n        let conn_fut =\n            RustlsConnector::from(self.config.clone()).connect(self.domain.as_ref().to_owned(), io);\n        let io = match self.timeout {\n            Some(timeout) => time::timeout(timeout, conn_fut)\n                .await\n                .map_err(|_| TlsError::HandshakeTimeout)?,\n            None => conn_fut.await,\n        }?;\n\n        // Generally we require ALPN to be negotiated, but if the user has\n        // explicitly set `assume_http2` to true, we'll allow it to be missing.\n        let (_, session) = io.get_ref();\n        let alpn_protocol = session.alpn_protocol();\n        if !(alpn_protocol == Some(ALPN_H2) || self.assume_http2) {\n            return Err(TlsError::H2NotNegotiated.into());\n        }\n        Ok(BoxedIo::new(TokioIo::new(io)))\n    }\n}\n\nimpl fmt::Debug for TlsConnector {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"TlsConnector\").finish()\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/service/user_agent.rs",
    "content": "use http::{HeaderValue, Request, header::USER_AGENT};\nuse std::task::{Context, Poll};\nuse tower_service::Service;\n\nconst TONIC_USER_AGENT: &str = concat!(\"tonic/\", env!(\"CARGO_PKG_VERSION\"));\n\n#[derive(Debug)]\npub(crate) struct UserAgent<T> {\n    inner: T,\n    user_agent: HeaderValue,\n}\n\nimpl<T> UserAgent<T> {\n    pub(crate) fn new(inner: T, user_agent: Option<HeaderValue>) -> Self {\n        let user_agent = user_agent\n            .map(|value| {\n                let mut buf = Vec::new();\n                buf.extend(value.as_bytes());\n                buf.push(b' ');\n                buf.extend(TONIC_USER_AGENT.as_bytes());\n                HeaderValue::from_bytes(&buf).expect(\"user-agent should be valid\")\n            })\n            .unwrap_or_else(|| HeaderValue::from_static(TONIC_USER_AGENT));\n\n        Self { inner, user_agent }\n    }\n}\n\nimpl<T, ReqBody> Service<Request<ReqBody>> for UserAgent<T>\nwhere\n    T: Service<Request<ReqBody>>,\n{\n    type Response = T::Response;\n    type Error = T::Error;\n    type Future = T::Future;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {\n        if let Ok(Some(user_agent)) = req\n            .headers_mut()\n            .try_insert(USER_AGENT, self.user_agent.clone())\n        {\n            // The User-Agent header has already been set on the request. Let's\n            // append our user agent to the end.\n            let mut buf = Vec::new();\n            buf.extend(user_agent.as_bytes());\n            buf.push(b' ');\n            buf.extend(self.user_agent.as_bytes());\n            req.headers_mut().insert(\n                USER_AGENT,\n                HeaderValue::from_bytes(&buf).expect(\"user-agent should be valid\"),\n            );\n        }\n\n        self.inner.call(req)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    struct Svc;\n\n    #[test]\n    fn sets_default_if_no_custom_user_agent() {\n        assert_eq!(\n            UserAgent::new(Svc, None).user_agent,\n            HeaderValue::from_static(TONIC_USER_AGENT)\n        )\n    }\n\n    #[test]\n    fn prepends_custom_user_agent_to_default() {\n        assert_eq!(\n            UserAgent::new(Svc, Some(HeaderValue::from_static(\"Greeter 1.1\"))).user_agent,\n            HeaderValue::from_str(&format!(\"Greeter 1.1 {TONIC_USER_AGENT}\")).unwrap()\n        )\n    }\n\n    struct TestSvc {\n        pub expected_user_agent: String,\n    }\n\n    impl Service<Request<()>> for TestSvc {\n        type Response = ();\n        type Error = ();\n        type Future = std::future::Ready<Result<(), ()>>;\n\n        fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n\n        fn call(&mut self, req: Request<()>) -> Self::Future {\n            let user_agent = req.headers().get(USER_AGENT).unwrap().to_str().unwrap();\n            assert_eq!(user_agent, self.expected_user_agent);\n            std::future::ready(Ok(()))\n        }\n    }\n\n    #[tokio::test]\n    async fn sets_default_user_agent_if_none_present() {\n        let expected_user_agent = TONIC_USER_AGENT.to_string();\n        let mut ua = UserAgent::new(\n            TestSvc {\n                expected_user_agent,\n            },\n            None,\n        );\n        let _ = ua.call(Request::default()).await;\n    }\n\n    #[tokio::test]\n    async fn sets_custom_user_agent_if_none_present() {\n        let expected_user_agent = format!(\"Greeter 1.1 {TONIC_USER_AGENT}\");\n        let mut ua = UserAgent::new(\n            TestSvc {\n                expected_user_agent,\n            },\n            Some(HeaderValue::from_static(\"Greeter 1.1\")),\n        );\n        let _ = ua.call(Request::default()).await;\n    }\n\n    #[tokio::test]\n    async fn appends_default_user_agent_to_request_user_agent() {\n        let mut req = Request::default();\n        req.headers_mut()\n            .insert(USER_AGENT, HeaderValue::from_static(\"request-ua/x.y\"));\n\n        let expected_user_agent = format!(\"request-ua/x.y {TONIC_USER_AGENT}\");\n        let mut ua = UserAgent::new(\n            TestSvc {\n                expected_user_agent,\n            },\n            None,\n        );\n        let _ = ua.call(req).await;\n    }\n\n    #[tokio::test]\n    async fn appends_custom_user_agent_to_request_user_agent() {\n        let mut req = Request::default();\n        req.headers_mut()\n            .insert(USER_AGENT, HeaderValue::from_static(\"request-ua/x.y\"));\n\n        let expected_user_agent = format!(\"request-ua/x.y Greeter 1.1 {TONIC_USER_AGENT}\");\n        let mut ua = UserAgent::new(\n            TestSvc {\n                expected_user_agent,\n            },\n            Some(HeaderValue::from_static(\"Greeter 1.1\")),\n        );\n        let _ = ua.call(req).await;\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/tls.rs",
    "content": "use super::service::TlsConnector;\nuse crate::transport::{\n    Error,\n    tls::{Certificate, Identity},\n};\nuse http::Uri;\nuse std::time::Duration;\nuse tokio_rustls::rustls::pki_types::TrustAnchor;\n\n/// Configures TLS settings for endpoints.\n#[derive(Debug, Clone, Default)]\npub struct ClientTlsConfig {\n    domain: Option<String>,\n    certs: Vec<Certificate>,\n    trust_anchors: Vec<TrustAnchor<'static>>,\n    identity: Option<Identity>,\n    assume_http2: bool,\n    #[cfg(feature = \"tls-native-roots\")]\n    with_native_roots: bool,\n    #[cfg(feature = \"tls-webpki-roots\")]\n    with_webpki_roots: bool,\n    use_key_log: bool,\n    timeout: Option<Duration>,\n}\n\nimpl ClientTlsConfig {\n    /// Creates a new `ClientTlsConfig` using Rustls.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Sets the domain name against which to verify the server's TLS certificate.\n    pub fn domain_name(self, domain_name: impl Into<String>) -> Self {\n        ClientTlsConfig {\n            domain: Some(domain_name.into()),\n            ..self\n        }\n    }\n\n    /// Adds the CA Certificate against which to verify the server's TLS certificate.\n    pub fn ca_certificate(self, ca_certificate: Certificate) -> Self {\n        let mut certs = self.certs;\n        certs.push(ca_certificate);\n        ClientTlsConfig { certs, ..self }\n    }\n\n    /// Adds the multiple CA Certificates against which to verify the server's TLS certificate.\n    pub fn ca_certificates(self, ca_certificates: impl IntoIterator<Item = Certificate>) -> Self {\n        let mut certs = self.certs;\n        certs.extend(ca_certificates);\n        ClientTlsConfig { certs, ..self }\n    }\n\n    /// Adds the trust anchor which to verify the server's TLS certificate.\n    pub fn trust_anchor(self, trust_anchor: TrustAnchor<'static>) -> Self {\n        let mut trust_anchors = self.trust_anchors;\n        trust_anchors.push(trust_anchor);\n        ClientTlsConfig {\n            trust_anchors,\n            ..self\n        }\n    }\n\n    /// Adds the multiple trust anchors which to verify the server's TLS certificate.\n    pub fn trust_anchors(\n        mut self,\n        trust_anchors: impl IntoIterator<Item = TrustAnchor<'static>>,\n    ) -> Self {\n        self.trust_anchors.extend(trust_anchors);\n        self\n    }\n\n    /// Sets the client identity to present to the server.\n    pub fn identity(self, identity: Identity) -> Self {\n        ClientTlsConfig {\n            identity: Some(identity),\n            ..self\n        }\n    }\n\n    /// If true, the connector should assume that the server supports HTTP/2,\n    /// even if it doesn't provide protocol negotiation via ALPN.\n    pub fn assume_http2(self, assume_http2: bool) -> Self {\n        ClientTlsConfig {\n            assume_http2,\n            ..self\n        }\n    }\n\n    /// Use key log as specified by the `SSLKEYLOGFILE` environment variable.\n    pub fn use_key_log(self) -> Self {\n        ClientTlsConfig {\n            use_key_log: true,\n            ..self\n        }\n    }\n\n    /// Enables the platform's trusted certs.\n    #[cfg(feature = \"tls-native-roots\")]\n    pub fn with_native_roots(self) -> Self {\n        ClientTlsConfig {\n            with_native_roots: true,\n            ..self\n        }\n    }\n\n    /// Enables the webpki roots.\n    #[cfg(feature = \"tls-webpki-roots\")]\n    pub fn with_webpki_roots(self) -> Self {\n        ClientTlsConfig {\n            with_webpki_roots: true,\n            ..self\n        }\n    }\n\n    /// Activates all TLS roots enabled through `tls-*-roots` feature flags\n    pub fn with_enabled_roots(self) -> Self {\n        let config = self;\n\n        #[cfg(feature = \"tls-native-roots\")]\n        let config = config.with_native_roots();\n        #[cfg(feature = \"tls-webpki-roots\")]\n        let config = config.with_webpki_roots();\n\n        config\n    }\n\n    /// Sets the timeout for the TLS handshake.\n    pub fn timeout(self, timeout: Duration) -> Self {\n        ClientTlsConfig {\n            timeout: Some(timeout),\n            ..self\n        }\n    }\n\n    pub(crate) fn into_tls_connector(self, uri: &Uri) -> Result<TlsConnector, crate::BoxError> {\n        let domain = match &self.domain {\n            Some(domain) => domain,\n            None => uri.host().ok_or_else(Error::new_invalid_uri)?,\n        };\n        TlsConnector::new(\n            self.certs,\n            self.trust_anchors,\n            self.identity,\n            domain,\n            self.assume_http2,\n            self.use_key_log,\n            self.timeout,\n            #[cfg(feature = \"tls-native-roots\")]\n            self.with_native_roots,\n            #[cfg(feature = \"tls-webpki-roots\")]\n            self.with_webpki_roots,\n        )\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/channel/uds_connector.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse http::Uri;\nuse hyper_util::rt::TokioIo;\n\nuse tower::Service;\n\nuse crate::status::ConnectError;\n\n#[cfg(not(target_os = \"windows\"))]\nuse tokio::net::UnixStream;\n\n#[cfg(not(target_os = \"windows\"))]\nasync fn connect_uds(uds_path: String) -> Result<UnixStream, ConnectError> {\n    UnixStream::connect(uds_path)\n        .await\n        .map_err(|err| ConnectError(From::from(err)))\n}\n\n// Dummy type that will allow us to compile and match trait bounds\n// but is never used.\n#[cfg(target_os = \"windows\")]\n#[allow(dead_code)]\ntype UnixStream = tokio::io::DuplexStream;\n\n#[cfg(target_os = \"windows\")]\nasync fn connect_uds(_uds_path: String) -> Result<UnixStream, ConnectError> {\n    Err(ConnectError(\n        \"uds connections are not allowed on windows\".into(),\n    ))\n}\n\npub(crate) struct UdsConnector {\n    uds_filepath: String,\n}\n\nimpl UdsConnector {\n    pub(crate) fn new(uds_filepath: &str) -> Self {\n        UdsConnector {\n            uds_filepath: uds_filepath.to_string(),\n        }\n    }\n}\n\nimpl Service<Uri> for UdsConnector {\n    type Response = TokioIo<UnixStream>;\n    type Error = ConnectError;\n    type Future = UdsConnecting;\n\n    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Poll::Ready(Ok(()))\n    }\n\n    fn call(&mut self, _: Uri) -> Self::Future {\n        let uds_path = self.uds_filepath.clone();\n        let fut = async move {\n            let stream = connect_uds(uds_path).await?;\n            Ok(TokioIo::new(stream))\n        };\n        UdsConnecting {\n            inner: Box::pin(fut),\n        }\n    }\n}\n\ntype ConnectResult = Result<TokioIo<UnixStream>, ConnectError>;\n\npub(crate) struct UdsConnecting {\n    inner: Pin<Box<dyn Future<Output = ConnectResult> + Send>>,\n}\n\nimpl Future for UdsConnecting {\n    type Output = ConnectResult;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.get_mut().inner.as_mut().poll(cx)\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/error.rs",
    "content": "use std::{error::Error as StdError, fmt};\n\ntype Source = Box<dyn StdError + Send + Sync + 'static>;\n\n/// Error's that originate from the client or server;\npub struct Error {\n    inner: ErrorImpl,\n}\n\nstruct ErrorImpl {\n    kind: Kind,\n    source: Option<Source>,\n}\n\n#[derive(Debug)]\npub(crate) enum Kind {\n    Transport,\n    #[cfg(feature = \"channel\")]\n    InvalidUri,\n    #[cfg(feature = \"channel\")]\n    InvalidUserAgent,\n    #[cfg(all(feature = \"_tls-any\", feature = \"channel\"))]\n    InvalidTlsConfigForUds,\n}\n\nimpl Error {\n    pub(crate) fn new(kind: Kind) -> Self {\n        Self {\n            inner: ErrorImpl { kind, source: None },\n        }\n    }\n\n    pub(crate) fn with(mut self, source: impl Into<Source>) -> Self {\n        self.inner.source = Some(source.into());\n        self\n    }\n\n    pub(crate) fn from_source(source: impl Into<crate::BoxError>) -> Self {\n        Error::new(Kind::Transport).with(source)\n    }\n\n    #[cfg(feature = \"channel\")]\n    pub(crate) fn new_invalid_uri() -> Self {\n        Error::new(Kind::InvalidUri)\n    }\n\n    #[cfg(feature = \"channel\")]\n    pub(crate) fn new_invalid_user_agent() -> Self {\n        Error::new(Kind::InvalidUserAgent)\n    }\n\n    fn description(&self) -> &str {\n        match &self.inner.kind {\n            Kind::Transport => \"transport error\",\n            #[cfg(feature = \"channel\")]\n            Kind::InvalidUri => \"invalid URI\",\n            #[cfg(feature = \"channel\")]\n            Kind::InvalidUserAgent => \"user agent is not a valid header value\",\n            #[cfg(all(feature = \"_tls-any\", feature = \"channel\"))]\n            Kind::InvalidTlsConfigForUds => \"cannot apply TLS config for unix domain socket\",\n        }\n    }\n}\n\nimpl fmt::Debug for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let mut f = f.debug_tuple(\"tonic::transport::Error\");\n\n        f.field(&self.inner.kind);\n\n        if let Some(source) = &self.inner.source {\n            f.field(source);\n        }\n\n        f.finish()\n    }\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.description())\n    }\n}\n\nimpl StdError for Error {\n    fn source(&self) -> Option<&(dyn StdError + 'static)> {\n        self.inner\n            .source\n            .as_ref()\n            .map(|source| &**source as &(dyn StdError + 'static))\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/mod.rs",
    "content": "//! Batteries included server and client.\n//!\n//! This module provides a set of batteries included, fully featured and\n//! fast set of HTTP/2 server and client's. These components each provide a\n//! `rustls` tls backend when the respective feature flag is enabled, and\n//! provides builders to configure transport behavior.\n//!\n//! # Features\n//!\n//! - TLS support via [rustls].\n//! - Load balancing\n//! - Timeouts\n//! - Concurrency Limits\n//! - Rate limiting\n//!\n//! # Examples\n//!\n//! ## Client\n//!\n//! ```no_run\n//! # #[cfg(feature = \"rustls\")]\n//! # use tonic::transport::{Channel, Certificate, ClientTlsConfig};\n//! # use std::time::Duration;\n//! # use tonic::client::GrpcService;;\n//! # use http::Request;\n//! # #[cfg(feature = \"rustls\")]\n//! # async fn do_thing() -> Result<(), Box<dyn std::error::Error>> {\n//! let cert = std::fs::read_to_string(\"ca.pem\")?;\n//!\n//! let mut channel = Channel::from_static(\"https://example.com\")\n//!     .tls_config(ClientTlsConfig::new()\n//!         .ca_certificate(Certificate::from_pem(&cert))\n//!         .domain_name(\"example.com\".to_string()))?\n//!     .timeout(Duration::from_secs(5))\n//!     .rate_limit(5, Duration::from_secs(1))\n//!     .concurrency_limit(256)\n//!     .connect()\n//!     .await?;\n//!\n//! channel.call(Request::new(tonic::body::empty_body())).await?;\n//! # Ok(())\n//! # }\n//! ```\n//!\n//! ## Server\n//!\n//! ```no_run\n//! # use std::convert::Infallible;\n//! # #[cfg(feature = \"rustls\")]\n//! # use tonic::transport::{Server, Identity, ServerTlsConfig};\n//! # use tonic::body::Body;\n//! # use tower::Service;\n//! # #[cfg(feature = \"rustls\")]\n//! # async fn do_thing() -> Result<(), Box<dyn std::error::Error>> {\n//! # #[derive(Clone)]\n//! # pub struct Svc;\n//! # impl Service<hyper::Request<Body>> for Svc {\n//! #   type Response = hyper::Response<Body>;\n//! #   type Error = Infallible;\n//! #   type Future = std::future::Ready<Result<Self::Response, Self::Error>>;\n//! #   fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {\n//! #       Ok(()).into()\n//! #  }\n//! #   fn call(&mut self, _req: hyper::Request<Body>) -> Self::Future {\n//! #       unimplemented!()\n//! #   }\n//! # }\n//! # impl tonic::server::NamedService for Svc {\n//! # const NAME: &'static str = \"some_svc\";\n//! # }\n//! # let my_svc = Svc;\n//! let cert = std::fs::read_to_string(\"server.pem\")?;\n//! let key = std::fs::read_to_string(\"server.key\")?;\n//!\n//! let addr = \"[::1]:50051\".parse()?;\n//!\n//! Server::builder()\n//!     .tls_config(ServerTlsConfig::new()\n//!         .identity(Identity::from_pem(&cert, &key)))?\n//!     .concurrency_limit_per_connection(256)\n//!     .add_service(my_svc)\n//!     .serve(addr)\n//!     .await?;\n//!\n//! # Ok(())\n//! # }\n//! ```\n//!\n//! [rustls]: https://docs.rs/rustls/0.16.0/rustls/\n\n#[cfg(feature = \"channel\")]\npub mod channel;\n#[cfg(feature = \"server\")]\npub mod server;\n\nmod error;\nmod service;\n#[cfg(feature = \"_tls-any\")]\nmod tls;\n\n#[doc(inline)]\n#[cfg(feature = \"channel\")]\npub use self::channel::{Channel, Endpoint};\npub use self::error::Error;\n#[doc(inline)]\n#[cfg(feature = \"server\")]\npub use self::server::Server;\n\n#[cfg(feature = \"_tls-any\")]\npub use self::tls::Certificate;\npub use hyper::{Uri, body::Body};\n#[cfg(feature = \"_tls-any\")]\npub use tokio_rustls::rustls::pki_types::CertificateDer;\n\n#[cfg(all(feature = \"channel\", feature = \"_tls-any\"))]\npub use self::channel::ClientTlsConfig;\n#[cfg(all(feature = \"server\", feature = \"_tls-any\"))]\npub use self::server::ServerTlsConfig;\n#[cfg(feature = \"_tls-any\")]\npub use self::tls::Identity;\n"
  },
  {
    "path": "tonic/src/transport/server/conn.rs",
    "content": "use std::net::SocketAddr;\nuse tokio::net::TcpStream;\n\n#[cfg(feature = \"tls-connect-info\")]\nuse std::sync::Arc;\n#[cfg(feature = \"tls-connect-info\")]\nuse tokio_rustls::rustls::pki_types::CertificateDer;\n#[cfg(feature = \"tls-connect-info\")]\nuse tokio_rustls::server::TlsStream;\n\n/// Trait that connected IO resources implement and use to produce info about the connection.\n///\n/// The goal for this trait is to allow users to implement\n/// custom IO types that can still provide the same connection\n/// metadata.\n///\n/// # Example\n///\n/// The `ConnectInfo` returned will be accessible through [request extensions][ext]:\n///\n/// ```\n/// use tonic::{Request, transport::server::Connected};\n///\n/// // A `Stream` that yields connections\n/// struct MyConnector {}\n///\n/// // Return metadata about the connection as `MyConnectInfo`\n/// impl Connected for MyConnector {\n///     type ConnectInfo = MyConnectInfo;\n///\n///     fn connect_info(&self) -> Self::ConnectInfo {\n///         MyConnectInfo {}\n///     }\n/// }\n///\n/// #[derive(Clone)]\n/// struct MyConnectInfo {\n///     // Metadata about your connection\n/// }\n///\n/// // The connect info can be accessed through request extensions:\n/// # fn foo(request: Request<()>) {\n/// let connect_info: &MyConnectInfo = request\n///     .extensions()\n///     .get::<MyConnectInfo>()\n///     .expect(\"bug in tonic\");\n/// # }\n/// ```\n///\n/// [ext]: crate::Request::extensions\npub trait Connected {\n    /// The connection info type the IO resources generates.\n    // all these bounds are necessary to set this as a request extension\n    type ConnectInfo: Clone + Send + Sync + 'static;\n\n    /// Create type holding information about the connection.\n    fn connect_info(&self) -> Self::ConnectInfo;\n}\n\n/// Connection info for standard TCP streams.\n///\n/// This type will be accessible through [request extensions][ext] if you're using the default\n/// non-TLS connector.\n///\n/// See [`Connected`] for more details.\n///\n/// [ext]: crate::Request::extensions\n#[derive(Debug, Clone)]\npub struct TcpConnectInfo {\n    /// Returns the local address of this connection.\n    pub local_addr: Option<SocketAddr>,\n    /// Returns the remote (peer) address of this connection.\n    pub remote_addr: Option<SocketAddr>,\n}\n\nimpl TcpConnectInfo {\n    /// Return the local address the IO resource is connected.\n    pub fn local_addr(&self) -> Option<SocketAddr> {\n        self.local_addr\n    }\n\n    /// Return the remote address the IO resource is connected too.\n    pub fn remote_addr(&self) -> Option<SocketAddr> {\n        self.remote_addr\n    }\n}\n\nimpl Connected for TcpStream {\n    type ConnectInfo = TcpConnectInfo;\n\n    fn connect_info(&self) -> Self::ConnectInfo {\n        TcpConnectInfo {\n            local_addr: self.local_addr().ok(),\n            remote_addr: self.peer_addr().ok(),\n        }\n    }\n}\n\nimpl Connected for tokio::io::DuplexStream {\n    type ConnectInfo = ();\n\n    fn connect_info(&self) -> Self::ConnectInfo {}\n}\n\n#[cfg(feature = \"tls-connect-info\")]\nimpl<T> Connected for TlsStream<T>\nwhere\n    T: Connected,\n{\n    type ConnectInfo = TlsConnectInfo<T::ConnectInfo>;\n\n    fn connect_info(&self) -> Self::ConnectInfo {\n        let (inner, session) = self.get_ref();\n        let inner = inner.connect_info();\n\n        let certs = session\n            .peer_certificates()\n            .map(|certs| certs.to_owned().into());\n\n        TlsConnectInfo { inner, certs }\n    }\n}\n\n/// Connection info for TLS streams.\n///\n/// This type will be accessible through [request extensions][ext] if you're using a TLS connector.\n///\n/// See [`Connected`] for more details.\n///\n/// [ext]: crate::Request::extensions\n#[cfg(feature = \"tls-connect-info\")]\n#[derive(Debug, Clone)]\npub struct TlsConnectInfo<T> {\n    inner: T,\n    certs: Option<Arc<Vec<CertificateDer<'static>>>>,\n}\n\n#[cfg(feature = \"tls-connect-info\")]\nimpl<T> TlsConnectInfo<T> {\n    /// Get a reference to the underlying connection info.\n    pub fn get_ref(&self) -> &T {\n        &self.inner\n    }\n\n    /// Get a mutable reference to the underlying connection info.\n    pub fn get_mut(&mut self) -> &mut T {\n        &mut self.inner\n    }\n\n    /// Return the set of connected peer TLS certificates.\n    pub fn peer_certs(&self) -> Option<Arc<Vec<CertificateDer<'static>>>> {\n        self.certs.clone()\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/server/display_error_stack.rs",
    "content": "use std::error::Error;\nuse std::fmt;\nuse std::fmt::{Display, Formatter};\n\npub(crate) struct DisplayErrorStack<'a>(pub(crate) &'a (dyn Error + 'static));\n\nimpl<'a> Display for DisplayErrorStack<'a> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.0)?;\n        let mut next = self.0.source();\n        while let Some(err) = next {\n            write!(f, \": {err}\")?;\n            next = err.source();\n        }\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::transport::server::display_error_stack::DisplayErrorStack;\n    use std::error::Error;\n    use std::fmt;\n    use std::fmt::{Display, Formatter};\n    use std::sync::Arc;\n\n    #[test]\n    fn test_display_error_stack() {\n        #[derive(Debug)]\n        struct TestError(&'static str, Option<Arc<TestError>>);\n\n        impl Display for TestError {\n            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n                write!(f, \"{}\", self.0)\n            }\n        }\n\n        impl Error for TestError {\n            fn source(&self) -> Option<&(dyn Error + 'static)> {\n                self.1.as_ref().map(|e| e as &(dyn Error + 'static))\n            }\n        }\n\n        let a = Arc::new(TestError(\"a\", None));\n        let b = Arc::new(TestError(\"b\", Some(a.clone())));\n        let c = Arc::new(TestError(\"c\", Some(b.clone())));\n\n        assert_eq!(\"a\", DisplayErrorStack(&a).to_string());\n        assert_eq!(\"b: a\", DisplayErrorStack(&b).to_string());\n        assert_eq!(\"c: b: a\", DisplayErrorStack(&c).to_string());\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/server/incoming.rs",
    "content": "use std::{\n    net::{SocketAddr, TcpListener as StdTcpListener},\n    pin::Pin,\n    task::{Context, Poll},\n    time::Duration,\n};\n\nuse socket2::TcpKeepalive;\nuse tokio::net::{TcpListener, TcpStream};\nuse tokio_stream::{Stream, wrappers::TcpListenerStream};\nuse tracing::warn;\n\n/// Binds a socket address for a [Router](super::Router)\n///\n/// An incoming stream, usable with [Router::serve_with_incoming](super::Router::serve_with_incoming),\n/// of `AsyncRead + AsyncWrite` that communicate with clients that connect to a socket address.\n#[derive(Debug)]\npub struct TcpIncoming {\n    inner: TcpListenerStream,\n    nodelay: Option<bool>,\n    keepalive: Option<TcpKeepalive>,\n    keepalive_time: Option<Duration>,\n    keepalive_interval: Option<Duration>,\n    keepalive_retries: Option<u32>,\n}\n\nimpl TcpIncoming {\n    /// Creates an instance by binding (opening) the specified socket address.\n    ///\n    /// Returns a TcpIncoming if the socket address was successfully bound.\n    ///\n    /// # Examples\n    /// ```no_run\n    /// # use tower_service::Service;\n    /// # use http::{request::Request, response::Response};\n    /// # use tonic::{body::Body, server::NamedService, transport::{Server, server::TcpIncoming}};\n    /// # use core::convert::Infallible;\n    /// # use std::error::Error;\n    /// # fn main() { }  // Cannot have type parameters, hence instead define:\n    /// # fn run<S>(some_service: S) -> Result<(), Box<dyn Error + Send + Sync>>\n    /// # where\n    /// #   S: Service<Request<Body>, Response = Response<Body>, Error = Infallible> + NamedService + Clone + Send + Sync + 'static,\n    /// #   S::Future: Send + 'static,\n    /// # {\n    /// // Find a free port\n    /// let mut port = 1322;\n    /// let tinc = loop {\n    ///    let addr = format!(\"127.0.0.1:{}\", port).parse().unwrap();\n    ///    match TcpIncoming::bind(addr) {\n    ///       Ok(t) => break t,\n    ///       Err(_) => port += 1\n    ///    }\n    /// };\n    /// Server::builder()\n    ///    .add_service(some_service)\n    ///    .serve_with_incoming(tinc);\n    /// # Ok(())\n    /// # }\n    pub fn bind(addr: SocketAddr) -> std::io::Result<Self> {\n        let std_listener = StdTcpListener::bind(addr)?;\n        std_listener.set_nonblocking(true)?;\n\n        Ok(TcpListener::from_std(std_listener)?.into())\n    }\n\n    /// Sets the `TCP_NODELAY` option on the accepted connection.\n    pub fn with_nodelay(self, nodelay: Option<bool>) -> Self {\n        Self { nodelay, ..self }\n    }\n\n    /// Sets the `TCP_KEEPALIVE` option on the accepted connection.\n    pub fn with_keepalive(self, keepalive_time: Option<Duration>) -> Self {\n        Self {\n            keepalive_time,\n            keepalive: make_keepalive(\n                keepalive_time,\n                self.keepalive_interval,\n                self.keepalive_retries,\n            ),\n            ..self\n        }\n    }\n\n    /// Sets the `TCP_KEEPINTVL` option on the accepted connection.\n    pub fn with_keepalive_interval(self, keepalive_interval: Option<Duration>) -> Self {\n        Self {\n            keepalive_interval,\n            keepalive: make_keepalive(\n                self.keepalive_time,\n                keepalive_interval,\n                self.keepalive_retries,\n            ),\n            ..self\n        }\n    }\n\n    /// Sets the `TCP_KEEPCNT` option on the accepted connection.\n    pub fn with_keepalive_retries(self, keepalive_retries: Option<u32>) -> Self {\n        Self {\n            keepalive_retries,\n            keepalive: make_keepalive(\n                self.keepalive_time,\n                self.keepalive_interval,\n                keepalive_retries,\n            ),\n            ..self\n        }\n    }\n\n    /// Returns the local address that this tcp incoming is bound to.\n    pub fn local_addr(&self) -> std::io::Result<SocketAddr> {\n        self.inner.as_ref().local_addr()\n    }\n}\n\nimpl From<TcpListener> for TcpIncoming {\n    fn from(listener: TcpListener) -> Self {\n        Self {\n            inner: TcpListenerStream::new(listener),\n            nodelay: None,\n            keepalive: None,\n            keepalive_time: None,\n            keepalive_interval: None,\n            keepalive_retries: None,\n        }\n    }\n}\n\nimpl Stream for TcpIncoming {\n    type Item = std::io::Result<TcpStream>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let polled = Pin::new(&mut self.inner).poll_next(cx);\n\n        if let Poll::Ready(Some(Ok(stream))) = &polled {\n            set_accepted_socket_options(stream, self.nodelay, &self.keepalive);\n        }\n\n        polled\n    }\n}\n\n// Consistent with hyper-0.14, this function does not return an error.\nfn set_accepted_socket_options(\n    stream: &TcpStream,\n    nodelay: Option<bool>,\n    keepalive: &Option<TcpKeepalive>,\n) {\n    if let Some(nodelay) = nodelay {\n        if let Err(e) = stream.set_nodelay(nodelay) {\n            warn!(\"error trying to set TCP_NODELAY: {e}\");\n        }\n    }\n\n    if let Some(keepalive) = keepalive {\n        let sock_ref = socket2::SockRef::from(&stream);\n        if let Err(e) = sock_ref.set_tcp_keepalive(keepalive) {\n            warn!(\"error trying to set TCP_KEEPALIVE: {e}\");\n        }\n    }\n}\n\nfn make_keepalive(\n    keepalive_time: Option<Duration>,\n    keepalive_interval: Option<Duration>,\n    keepalive_retries: Option<u32>,\n) -> Option<TcpKeepalive> {\n    let mut dirty = false;\n    let mut keepalive = TcpKeepalive::new();\n    if let Some(t) = keepalive_time {\n        keepalive = keepalive.with_time(t);\n        dirty = true;\n    }\n\n    #[cfg(\n        // See https://docs.rs/socket2/0.5.8/src/socket2/lib.rs.html#511-525\n        any(\n            target_os = \"android\",\n            target_os = \"dragonfly\",\n            target_os = \"freebsd\",\n            target_os = \"fuchsia\",\n            target_os = \"illumos\",\n            target_os = \"ios\",\n            target_os = \"visionos\",\n            target_os = \"linux\",\n            target_os = \"macos\",\n            target_os = \"netbsd\",\n            target_os = \"tvos\",\n            target_os = \"watchos\",\n            target_os = \"windows\",\n        )\n    )]\n    if let Some(t) = keepalive_interval {\n        keepalive = keepalive.with_interval(t);\n        dirty = true;\n    }\n\n    #[cfg(\n        // See https://docs.rs/socket2/0.5.8/src/socket2/lib.rs.html#557-570\n        any(\n            target_os = \"android\",\n            target_os = \"dragonfly\",\n            target_os = \"freebsd\",\n            target_os = \"fuchsia\",\n            target_os = \"illumos\",\n            target_os = \"ios\",\n            target_os = \"visionos\",\n            target_os = \"linux\",\n            target_os = \"macos\",\n            target_os = \"netbsd\",\n            target_os = \"tvos\",\n            target_os = \"watchos\",\n        )\n    )]\n    if let Some(r) = keepalive_retries {\n        keepalive = keepalive.with_retries(r);\n        dirty = true;\n    }\n\n    // avoid clippy errors for targets that do not use these fields.\n    let _ = keepalive_retries;\n    let _ = keepalive_interval;\n\n    dirty.then_some(keepalive)\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::transport::server::TcpIncoming;\n    #[tokio::test]\n    async fn one_tcpincoming_at_a_time() {\n        let addr = \"127.0.0.1:1322\".parse().unwrap();\n        {\n            let _t1 = TcpIncoming::bind(addr).unwrap();\n            let _t2 = TcpIncoming::bind(addr).unwrap_err();\n        }\n        let _t3 = TcpIncoming::bind(addr).unwrap();\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/server/io_stream.rs",
    "content": "#[cfg(feature = \"_tls-any\")]\nuse std::future::Future;\n#[cfg(feature = \"_tls-any\")]\nuse std::pin::pin;\nuse std::{\n    io,\n    ops::ControlFlow,\n    pin::Pin,\n    task::{Context, Poll, ready},\n};\n\nuse pin_project::pin_project;\nuse tokio::io::{AsyncRead, AsyncWrite};\n#[cfg(feature = \"_tls-any\")]\nuse tokio::task::JoinSet;\nuse tokio_stream::Stream;\n#[cfg(feature = \"_tls-any\")]\nuse tokio_stream::StreamExt as _;\n\nuse super::service::ServerIo;\n#[cfg(feature = \"_tls-any\")]\nuse super::service::TlsAcceptor;\n\n#[cfg(feature = \"_tls-any\")]\nstruct State<IO>(TlsAcceptor, JoinSet<Result<ServerIo<IO>, crate::BoxError>>);\n\n#[pin_project]\npub(crate) struct ServerIoStream<S, IO, IE>\nwhere\n    S: Stream<Item = Result<IO, IE>>,\n{\n    #[pin]\n    inner: S,\n    #[cfg(feature = \"_tls-any\")]\n    state: Option<State<IO>>,\n}\n\nimpl<S, IO, IE> ServerIoStream<S, IO, IE>\nwhere\n    S: Stream<Item = Result<IO, IE>>,\n{\n    pub(crate) fn new(incoming: S, #[cfg(feature = \"_tls-any\")] tls: Option<TlsAcceptor>) -> Self {\n        Self {\n            inner: incoming,\n            #[cfg(feature = \"_tls-any\")]\n            state: tls.map(|tls| State(tls, JoinSet::new())),\n        }\n    }\n\n    fn poll_next_without_tls(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<ServerIo<IO>, crate::BoxError>>>\n    where\n        IE: Into<crate::BoxError>,\n    {\n        match ready!(self.as_mut().project().inner.poll_next(cx)) {\n            Some(Ok(io)) => Poll::Ready(Some(Ok(ServerIo::new_io(io)))),\n            Some(Err(e)) => match handle_tcp_accept_error(e) {\n                ControlFlow::Continue(()) => {\n                    cx.waker().wake_by_ref();\n                    Poll::Pending\n                }\n                ControlFlow::Break(e) => Poll::Ready(Some(Err(e))),\n            },\n            None => Poll::Ready(None),\n        }\n    }\n}\n\nimpl<S, IO, IE> Stream for ServerIoStream<S, IO, IE>\nwhere\n    S: Stream<Item = Result<IO, IE>>,\n    IO: AsyncRead + AsyncWrite + Unpin + Send + 'static,\n    IE: Into<crate::BoxError>,\n{\n    type Item = Result<ServerIo<IO>, crate::BoxError>;\n\n    #[cfg(not(feature = \"_tls-any\"))]\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        self.poll_next_without_tls(cx)\n    }\n\n    #[cfg(feature = \"_tls-any\")]\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let mut projected = self.as_mut().project();\n\n        let Some(State(tls, tasks)) = projected.state else {\n            return self.poll_next_without_tls(cx);\n        };\n\n        let select_output = ready!(pin!(select(&mut projected.inner, tasks)).poll(cx));\n\n        match select_output {\n            SelectOutput::Incoming(stream) => {\n                let tls = tls.clone();\n                tasks.spawn(async move {\n                    let io = tls.accept(stream).await?;\n                    Ok(ServerIo::new_tls_io(io))\n                });\n                cx.waker().wake_by_ref();\n                Poll::Pending\n            }\n\n            SelectOutput::Io(io) => Poll::Ready(Some(Ok(io))),\n\n            SelectOutput::TcpErr(e) => match handle_tcp_accept_error(e) {\n                ControlFlow::Continue(()) => {\n                    cx.waker().wake_by_ref();\n                    Poll::Pending\n                }\n                ControlFlow::Break(e) => Poll::Ready(Some(Err(e))),\n            },\n\n            SelectOutput::TlsErr(e) => {\n                tracing::debug!(error = %e, \"tls accept error\");\n                cx.waker().wake_by_ref();\n                Poll::Pending\n            }\n\n            SelectOutput::Done => Poll::Ready(None),\n        }\n    }\n}\n\nfn handle_tcp_accept_error(e: impl Into<crate::BoxError>) -> ControlFlow<crate::BoxError> {\n    let e = e.into();\n    tracing::debug!(error = %e, \"accept loop error\");\n    if let Some(e) = e.downcast_ref::<io::Error>() {\n        if matches!(\n            e.kind(),\n            io::ErrorKind::ConnectionAborted\n                | io::ErrorKind::ConnectionReset\n                | io::ErrorKind::BrokenPipe\n                | io::ErrorKind::Interrupted\n                | io::ErrorKind::WouldBlock\n                | io::ErrorKind::TimedOut\n        ) {\n            return ControlFlow::Continue(());\n        }\n    }\n\n    ControlFlow::Break(e)\n}\n\n#[cfg(feature = \"_tls-any\")]\nasync fn select<IO: 'static, IE>(\n    incoming: &mut (impl Stream<Item = Result<IO, IE>> + Unpin),\n    tasks: &mut JoinSet<Result<ServerIo<IO>, crate::BoxError>>,\n) -> SelectOutput<IO>\nwhere\n    IE: Into<crate::BoxError>,\n{\n    let incoming_stream_future = async {\n        match incoming.try_next().await {\n            Ok(Some(stream)) => SelectOutput::Incoming(stream),\n            Ok(None) => SelectOutput::Done,\n            Err(e) => SelectOutput::TcpErr(e.into()),\n        }\n    };\n\n    if tasks.is_empty() {\n        return incoming_stream_future.await;\n    }\n\n    tokio::select! {\n        stream = incoming_stream_future => stream,\n        accept = tasks.join_next() => {\n            match accept.expect(\"JoinSet should never end\") {\n                Ok(Ok(io)) => SelectOutput::Io(io),\n                Ok(Err(e)) => SelectOutput::TlsErr(e),\n                Err(e) => SelectOutput::TlsErr(e.into()),\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"_tls-any\")]\nenum SelectOutput<A> {\n    Incoming(A),\n    Io(ServerIo<A>),\n    TcpErr(crate::BoxError),\n    TlsErr(crate::BoxError),\n    Done,\n}\n"
  },
  {
    "path": "tonic/src/transport/server/mod.rs",
    "content": "//! Server implementation and builder.\n\nmod conn;\nmod display_error_stack;\nmod incoming;\nmod io_stream;\nmod service;\n#[cfg(feature = \"_tls-any\")]\nmod tls;\n#[cfg(unix)]\nmod unix;\n\nuse tokio_stream::StreamExt as _;\nuse tracing::{debug, trace};\n\n#[cfg(feature = \"router\")]\nuse crate::{server::NamedService, service::Routes};\n\n#[cfg(feature = \"router\")]\nuse std::convert::Infallible;\n\npub use conn::{Connected, TcpConnectInfo};\nuse hyper_util::{\n    rt::{TokioExecutor, TokioIo, TokioTimer},\n    server::conn::auto::{Builder as ConnectionBuilder, HttpServerConnExec},\n    service::TowerToHyperService,\n};\n#[cfg(feature = \"_tls-any\")]\npub use tls::ServerTlsConfig;\n\n#[cfg(feature = \"_tls-any\")]\npub use conn::TlsConnectInfo;\n\n#[cfg(feature = \"_tls-any\")]\nuse self::service::TlsAcceptor;\n\n#[cfg(unix)]\npub use unix::UdsConnectInfo;\n\npub use incoming::TcpIncoming;\n\n#[cfg(feature = \"_tls-any\")]\nuse crate::transport::Error;\n\nuse self::service::{ConnectInfoLayer, ServerIo};\nuse super::service::GrpcTimeout;\nuse crate::body::Body;\nuse crate::service::RecoverErrorLayer;\nuse crate::transport::server::display_error_stack::DisplayErrorStack;\nuse bytes::Bytes;\nuse http::{Request, Response};\nuse http_body_util::BodyExt;\nuse hyper::{body::Incoming, service::Service as HyperService};\nuse pin_project::pin_project;\nuse std::{\n    fmt,\n    future::{self, Future},\n    marker::PhantomData,\n    net::SocketAddr,\n    pin::{Pin, pin},\n    sync::Arc,\n    task::{Context, Poll, ready},\n    time::Duration,\n};\nuse tokio::io::{AsyncRead, AsyncWrite};\nuse tokio_stream::Stream;\nuse tower::{\n    Service, ServiceBuilder, ServiceExt,\n    layer::Layer,\n    layer::util::{Identity, Stack},\n    limit::concurrency::ConcurrencyLimitLayer,\n    load_shed::LoadShedLayer,\n    util::BoxCloneService,\n};\n\ntype BoxService = tower::util::BoxCloneService<Request<Body>, Response<Body>, crate::BoxError>;\ntype TraceInterceptor = Arc<dyn Fn(&http::Request<()>) -> tracing::Span + Send + Sync + 'static>;\n\nconst DEFAULT_HTTP2_KEEPALIVE_TIMEOUT: Duration = Duration::from_secs(20);\n\n/// A default batteries included `transport` server.\n///\n/// This provides an easy builder pattern style builder [`Server`] on top of\n/// `hyper` connections. This builder exposes easy configuration parameters\n/// for providing a fully featured http2 based gRPC server. This should provide\n/// a very good out of the box http2 server for use with tonic but is also a\n/// reference implementation that should be a good starting point for anyone\n/// wanting to create a more complex and/or specific implementation.\n#[derive(Clone)]\npub struct Server<L = Identity> {\n    trace_interceptor: Option<TraceInterceptor>,\n    concurrency_limit: Option<usize>,\n    load_shed: bool,\n    timeout: Option<Duration>,\n    #[cfg(feature = \"_tls-any\")]\n    tls: Option<TlsAcceptor>,\n    init_stream_window_size: Option<u32>,\n    init_connection_window_size: Option<u32>,\n    max_concurrent_streams: Option<u32>,\n    tcp_keepalive: Option<Duration>,\n    tcp_keepalive_interval: Option<Duration>,\n    tcp_keepalive_retries: Option<u32>,\n    tcp_nodelay: bool,\n    http2_keepalive_interval: Option<Duration>,\n    http2_keepalive_timeout: Duration,\n    http2_adaptive_window: Option<bool>,\n    http2_max_pending_accept_reset_streams: Option<usize>,\n    http2_max_local_error_reset_streams: Option<usize>,\n    http2_max_header_list_size: Option<u32>,\n    max_frame_size: Option<u32>,\n    accept_http1: bool,\n    service_builder: ServiceBuilder<L>,\n    max_connection_age: Option<Duration>,\n    max_connection_age_grace: Option<Duration>,\n}\n\nimpl Default for Server<Identity> {\n    fn default() -> Self {\n        Self {\n            trace_interceptor: None,\n            concurrency_limit: None,\n            load_shed: false,\n            timeout: None,\n            #[cfg(feature = \"_tls-any\")]\n            tls: None,\n            init_stream_window_size: None,\n            init_connection_window_size: None,\n            max_concurrent_streams: None,\n            tcp_keepalive: None,\n            tcp_keepalive_interval: None,\n            tcp_keepalive_retries: None,\n            tcp_nodelay: true,\n            http2_keepalive_interval: None,\n            http2_keepalive_timeout: DEFAULT_HTTP2_KEEPALIVE_TIMEOUT,\n            http2_adaptive_window: None,\n            http2_max_pending_accept_reset_streams: None,\n            http2_max_local_error_reset_streams: None,\n            http2_max_header_list_size: None,\n            max_frame_size: None,\n            accept_http1: false,\n            service_builder: Default::default(),\n            max_connection_age: None,\n            max_connection_age_grace: None,\n        }\n    }\n}\n\n/// A stack based [`Service`] router.\n#[cfg(feature = \"router\")]\n#[derive(Clone, Debug)]\npub struct Router<L = Identity> {\n    server: Server<L>,\n    routes: Routes,\n}\n\nimpl Server {\n    /// Create a new server builder that can configure a [`Server`].\n    pub fn builder() -> Self {\n        Self::default()\n    }\n}\n\nimpl<L> Server<L> {\n    /// Configure TLS for this server.\n    #[cfg(feature = \"_tls-any\")]\n    pub fn tls_config(self, tls_config: ServerTlsConfig) -> Result<Self, Error> {\n        Ok(Server {\n            tls: Some(tls_config.tls_acceptor().map_err(Error::from_source)?),\n            ..self\n        })\n    }\n\n    /// Set the concurrency limit applied to on requests inbound per connection.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use tonic::transport::Server;\n    /// # use tower_service::Service;\n    /// # let builder = Server::builder();\n    /// builder.concurrency_limit_per_connection(32);\n    /// ```\n    #[must_use]\n    pub fn concurrency_limit_per_connection(self, limit: usize) -> Self {\n        Server {\n            concurrency_limit: Some(limit),\n            ..self\n        }\n    }\n\n    /// Enable or disable load shedding. The default is disabled.\n    ///\n    /// When load shedding is enabled, if the service responds with not ready\n    /// the request will immediately be rejected with a\n    /// [`resource_exhausted`](https://docs.rs/tonic/latest/tonic/struct.Status.html#method.resource_exhausted) error.\n    /// The default is to buffer requests. This is especially useful in combination with\n    /// setting a concurrency limit per connection.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use tonic::transport::Server;\n    /// # use tower_service::Service;\n    /// # let builder = Server::builder();\n    /// builder.load_shed(true);\n    /// ```\n    #[must_use]\n    pub fn load_shed(self, load_shed: bool) -> Self {\n        Server { load_shed, ..self }\n    }\n\n    /// Set a timeout on for all request handlers.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use tonic::transport::Server;\n    /// # use tower_service::Service;\n    /// # use std::time::Duration;\n    /// # let builder = Server::builder();\n    /// builder.timeout(Duration::from_secs(30));\n    /// ```\n    #[must_use]\n    pub fn timeout(self, timeout: Duration) -> Self {\n        Server {\n            timeout: Some(timeout),\n            ..self\n        }\n    }\n\n    /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2\n    /// stream-level flow control.\n    ///\n    /// Default is 65,535\n    ///\n    /// [spec]: https://httpwg.org/specs/rfc9113.html#InitialWindowSize\n    #[must_use]\n    pub fn initial_stream_window_size(self, sz: impl Into<Option<u32>>) -> Self {\n        Server {\n            init_stream_window_size: sz.into(),\n            ..self\n        }\n    }\n\n    /// Sets the max connection-level flow control for HTTP2\n    ///\n    /// Default is 65,535\n    #[must_use]\n    pub fn initial_connection_window_size(self, sz: impl Into<Option<u32>>) -> Self {\n        Server {\n            init_connection_window_size: sz.into(),\n            ..self\n        }\n    }\n\n    /// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2\n    /// connections.\n    ///\n    /// Default is no limit (`None`).\n    ///\n    /// [spec]: https://httpwg.org/specs/rfc9113.html#n-stream-concurrency\n    #[must_use]\n    pub fn max_concurrent_streams(self, max: impl Into<Option<u32>>) -> Self {\n        Server {\n            max_concurrent_streams: max.into(),\n            ..self\n        }\n    }\n\n    /// Sets the maximum time option in milliseconds that a connection may exist\n    ///\n    /// Default is no limit (`None`).\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use tonic::transport::Server;\n    /// # use tower_service::Service;\n    /// # use std::time::Duration;\n    /// # let builder = Server::builder();\n    /// builder.max_connection_age(Duration::from_secs(60));\n    /// ```\n    #[must_use]\n    pub fn max_connection_age(self, max_connection_age: Duration) -> Self {\n        Server {\n            max_connection_age: Some(max_connection_age),\n            ..self\n        }\n    }\n\n    /// Sets the maximum duration that a connection may continue to exist\n    /// **after** the graceful shutdown period (`max_connection_age`) has elapsed.\n    ///\n    /// This timeout only takes effect *after* a connection has exceeded its\n    /// configured `max_connection_age`. Once that happens, the server will begin\n    /// graceful shutdown for the connection. If the connection does not close\n    /// gracefully within the `max_connection_age_grace` duration, the server will then\n    /// forcefully terminate it.\n    ///\n    /// If no `max_connection_age` is configured, this forced shutdown timeout will\n    /// **never trigger**, because the server will not know when to begin the\n    /// graceful shutdown phase.\n    ///\n    /// Default is no limit (`None`).\n    ///\n    /// ```\n    /// # use tonic::transport::Server;\n    /// # use tower_service::Service;\n    /// # use std::time::Duration;\n    /// # let builder = Server::builder();\n    /// builder.max_connection_age_grace(Duration::from_secs(60));\n    /// ```\n    #[must_use]\n    pub fn max_connection_age_grace(self, max_connection_age_grace: Duration) -> Self {\n        Server {\n            max_connection_age_grace: Some(max_connection_age_grace),\n            ..self\n        }\n    }\n\n    /// Set whether HTTP2 Ping frames are enabled on accepted connections.\n    ///\n    /// If `None` is specified, HTTP2 keepalive is disabled, otherwise the duration\n    /// specified will be the time interval between HTTP2 Ping frames.\n    /// The timeout for receiving an acknowledgement of the keepalive ping\n    /// can be set with [`Server::http2_keepalive_timeout`].\n    ///\n    /// Default is no HTTP2 keepalive (`None`)\n    ///\n    #[must_use]\n    pub fn http2_keepalive_interval(self, http2_keepalive_interval: Option<Duration>) -> Self {\n        Server {\n            http2_keepalive_interval,\n            ..self\n        }\n    }\n\n    /// Sets a timeout for receiving an acknowledgement of the keepalive ping.\n    ///\n    /// If the ping is not acknowledged within the timeout, the connection will be closed.\n    /// Does nothing if http2_keep_alive_interval is disabled.\n    ///\n    /// Default is 20 seconds.\n    ///\n    #[must_use]\n    pub fn http2_keepalive_timeout(mut self, http2_keepalive_timeout: Option<Duration>) -> Self {\n        if let Some(timeout) = http2_keepalive_timeout {\n            self.http2_keepalive_timeout = timeout;\n        }\n        self\n    }\n\n    /// Sets whether to use an adaptive flow control. Defaults to false.\n    /// Enabling this will override the limits set in http2_initial_stream_window_size and\n    /// http2_initial_connection_window_size.\n    #[must_use]\n    pub fn http2_adaptive_window(self, enabled: Option<bool>) -> Self {\n        Server {\n            http2_adaptive_window: enabled,\n            ..self\n        }\n    }\n\n    /// Configures the maximum number of pending reset streams allowed before a GOAWAY will be sent.\n    ///\n    /// This will default to whatever the default in h2 is. As of v0.3.17, it is 20.\n    ///\n    /// See <https://github.com/hyperium/hyper/issues/2877> for more information.\n    #[must_use]\n    pub fn http2_max_pending_accept_reset_streams(self, max: Option<usize>) -> Self {\n        Server {\n            http2_max_pending_accept_reset_streams: max,\n            ..self\n        }\n    }\n\n    /// Configures the maximum number of local reset streams allowed before a GOAWAY will be sent.\n    ///\n    /// This will default to whatever the default in hyper is.\n    #[must_use]\n    pub fn http2_max_local_error_reset_streams(self, max: Option<usize>) -> Self {\n        Server {\n            http2_max_local_error_reset_streams: max,\n            ..self\n        }\n    }\n\n    /// Set whether TCP keepalive messages are enabled on accepted connections.\n    ///\n    /// If `None` is specified, keepalive is disabled, otherwise the duration\n    /// specified will be the time to remain idle before sending TCP keepalive\n    /// probes.\n    ///\n    /// Important: This setting is ignored when using `serve_with_incoming`.\n    ///\n    /// Default is no keepalive (`None`)\n    ///\n    #[must_use]\n    pub fn tcp_keepalive(self, tcp_keepalive: Option<Duration>) -> Self {\n        Server {\n            tcp_keepalive,\n            ..self\n        }\n    }\n\n    /// Set the value of `TCP_KEEPINTVL` option for accepted connections.\n    ///\n    /// This option specifies the time interval between subsequent keepalive probes.\n    /// This setting only takes effect if [`tcp_keepalive`](Self::tcp_keepalive) is also set.\n    ///\n    /// Important: This setting is ignored when using `serve_with_incoming`.\n    ///\n    /// Default is `None` (system default).\n    ///\n    /// Note: This option is only available on some platforms (Linux, macOS, Windows, etc.).\n    #[must_use]\n    pub fn tcp_keepalive_interval(self, tcp_keepalive_interval: Option<Duration>) -> Self {\n        Server {\n            tcp_keepalive_interval,\n            ..self\n        }\n    }\n\n    /// Set the value of `TCP_KEEPCNT` option for accepted connections.\n    ///\n    /// This option specifies the maximum number of keepalive probes that should be sent\n    /// before dropping the connection.\n    /// This setting only takes effect if [`tcp_keepalive`](Self::tcp_keepalive) is also set.\n    ///\n    /// Important: This setting is ignored when using `serve_with_incoming`.\n    ///\n    /// Default is `None` (system default).\n    ///\n    /// Note: This option is only available on some platforms (Linux, macOS, Windows, etc.).\n    #[must_use]\n    pub fn tcp_keepalive_retries(self, tcp_keepalive_retries: Option<u32>) -> Self {\n        Server {\n            tcp_keepalive_retries,\n            ..self\n        }\n    }\n\n    /// Set the value of `TCP_NODELAY` option for accepted connections. Enabled by default.\n    ///\n    /// Important: This setting is ignored when using `serve_with_incoming`.\n    #[must_use]\n    pub fn tcp_nodelay(self, enabled: bool) -> Self {\n        Server {\n            tcp_nodelay: enabled,\n            ..self\n        }\n    }\n\n    /// Sets the max size of received header frames.\n    ///\n    /// This will default to whatever the default in hyper is. As of v1.4.1, it is 16 KiB.\n    #[must_use]\n    pub fn http2_max_header_list_size(self, max: impl Into<Option<u32>>) -> Self {\n        Server {\n            http2_max_header_list_size: max.into(),\n            ..self\n        }\n    }\n\n    /// Sets the maximum frame size to use for HTTP2.\n    ///\n    /// Passing `None` will do nothing.\n    ///\n    /// If not set, will default from underlying transport.\n    #[must_use]\n    pub fn max_frame_size(self, frame_size: impl Into<Option<u32>>) -> Self {\n        Server {\n            max_frame_size: frame_size.into(),\n            ..self\n        }\n    }\n\n    /// Allow this server to accept http1 requests.\n    ///\n    /// Accepting http1 requests is only useful when developing `grpc-web`\n    /// enabled services. If this setting is set to `true` but services are\n    /// not correctly configured to handle grpc-web requests, your server may\n    /// return confusing (but correct) protocol errors.\n    ///\n    /// Default is `false`.\n    #[must_use]\n    pub fn accept_http1(self, accept_http1: bool) -> Self {\n        Server {\n            accept_http1,\n            ..self\n        }\n    }\n\n    /// Intercept inbound headers and add a [`tracing::Span`] to each response future.\n    #[must_use]\n    pub fn trace_fn<F>(self, f: F) -> Self\n    where\n        F: Fn(&http::Request<()>) -> tracing::Span + Send + Sync + 'static,\n    {\n        Server {\n            trace_interceptor: Some(Arc::new(f)),\n            ..self\n        }\n    }\n\n    /// Create a router with the `S` typed service as the first service.\n    ///\n    /// This will clone the `Server` builder and create a router that will\n    /// route around different services.\n    #[cfg(feature = \"router\")]\n    pub fn add_service<S>(&mut self, svc: S) -> Router<L>\n    where\n        S: Service<Request<Body>, Error = Infallible>\n            + NamedService\n            + Clone\n            + Send\n            + Sync\n            + 'static,\n        S::Response: axum::response::IntoResponse,\n        S::Future: Send + 'static,\n        L: Clone,\n    {\n        Router::new(self.clone(), Routes::new(svc))\n    }\n\n    /// Create a router with the optional `S` typed service as the first service.\n    ///\n    /// This will clone the `Server` builder and create a router that will\n    /// route around different services.\n    ///\n    /// # Note\n    /// Even when the argument given is `None` this will capture *all* requests to this service name.\n    /// As a result, one cannot use this to toggle between two identically named implementations.\n    #[cfg(feature = \"router\")]\n    pub fn add_optional_service<S>(&mut self, svc: Option<S>) -> Router<L>\n    where\n        S: Service<Request<Body>, Error = Infallible>\n            + NamedService\n            + Clone\n            + Send\n            + Sync\n            + 'static,\n        S::Response: axum::response::IntoResponse,\n        S::Future: Send + 'static,\n        L: Clone,\n    {\n        let routes = svc.map(Routes::new).unwrap_or_default();\n        Router::new(self.clone(), routes)\n    }\n\n    /// Create a router with given [`Routes`].\n    ///\n    /// This will clone the `Server` builder and create a router that will\n    /// route around different services that were already added to the provided `routes`.\n    #[cfg(feature = \"router\")]\n    pub fn add_routes(&mut self, routes: Routes) -> Router<L>\n    where\n        L: Clone,\n    {\n        Router::new(self.clone(), routes)\n    }\n\n    /// Set the [Tower] [`Layer`] all services will be wrapped in.\n    ///\n    /// This enables using middleware from the [Tower ecosystem][eco].\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use tonic::transport::Server;\n    /// # use tower_service::Service;\n    /// use tower::timeout::TimeoutLayer;\n    /// use std::time::Duration;\n    ///\n    /// # let mut builder = Server::builder();\n    /// builder.layer(TimeoutLayer::new(Duration::from_secs(30)));\n    /// ```\n    ///\n    /// Note that timeouts should be set using [`Server::timeout`]. `TimeoutLayer` is only used\n    /// here as an example.\n    ///\n    /// You can build more complex layers using [`ServiceBuilder`]. Those layers can include\n    /// [interceptors]:\n    ///\n    /// ```\n    /// # use tonic::transport::Server;\n    /// # use tower_service::Service;\n    /// use tower::ServiceBuilder;\n    /// use std::time::Duration;\n    /// use tonic::{Request, Status, service::InterceptorLayer};\n    ///\n    /// fn auth_interceptor(request: Request<()>) -> Result<Request<()>, Status> {\n    ///     if valid_credentials(&request) {\n    ///         Ok(request)\n    ///     } else {\n    ///         Err(Status::unauthenticated(\"invalid credentials\"))\n    ///     }\n    /// }\n    ///\n    /// fn valid_credentials(request: &Request<()>) -> bool {\n    ///     // ...\n    ///     # true\n    /// }\n    ///\n    /// fn some_other_interceptor(request: Request<()>) -> Result<Request<()>, Status> {\n    ///     Ok(request)\n    /// }\n    ///\n    /// let layer = ServiceBuilder::new()\n    ///     .load_shed()\n    ///     .timeout(Duration::from_secs(30))\n    ///     .layer(InterceptorLayer::new(auth_interceptor))\n    ///     .layer(InterceptorLayer::new(some_other_interceptor))\n    ///     .into_inner();\n    ///\n    /// Server::builder().layer(layer);\n    /// ```\n    ///\n    /// [Tower]: https://github.com/tower-rs/tower\n    /// [`Layer`]: tower::layer::Layer\n    /// [eco]: https://github.com/tower-rs\n    /// [`ServiceBuilder`]: tower::ServiceBuilder\n    /// [interceptors]: crate::service::Interceptor\n    pub fn layer<NewLayer>(self, new_layer: NewLayer) -> Server<Stack<NewLayer, L>> {\n        Server {\n            service_builder: self.service_builder.layer(new_layer),\n            trace_interceptor: self.trace_interceptor,\n            concurrency_limit: self.concurrency_limit,\n            load_shed: self.load_shed,\n            timeout: self.timeout,\n            #[cfg(feature = \"_tls-any\")]\n            tls: self.tls,\n            init_stream_window_size: self.init_stream_window_size,\n            init_connection_window_size: self.init_connection_window_size,\n            max_concurrent_streams: self.max_concurrent_streams,\n            tcp_keepalive: self.tcp_keepalive,\n            tcp_keepalive_interval: self.tcp_keepalive_interval,\n            tcp_keepalive_retries: self.tcp_keepalive_retries,\n            tcp_nodelay: self.tcp_nodelay,\n            http2_keepalive_interval: self.http2_keepalive_interval,\n            http2_keepalive_timeout: self.http2_keepalive_timeout,\n            http2_adaptive_window: self.http2_adaptive_window,\n            http2_max_pending_accept_reset_streams: self.http2_max_pending_accept_reset_streams,\n            http2_max_header_list_size: self.http2_max_header_list_size,\n            http2_max_local_error_reset_streams: self.http2_max_local_error_reset_streams,\n            max_frame_size: self.max_frame_size,\n            accept_http1: self.accept_http1,\n            max_connection_age: self.max_connection_age,\n            max_connection_age_grace: self.max_connection_age_grace,\n        }\n    }\n\n    fn bind_incoming(&self, addr: SocketAddr) -> Result<TcpIncoming, super::Error> {\n        Ok(TcpIncoming::bind(addr)\n            .map_err(super::Error::from_source)?\n            .with_nodelay(Some(self.tcp_nodelay))\n            .with_keepalive(self.tcp_keepalive)\n            .with_keepalive_interval(self.tcp_keepalive_interval)\n            .with_keepalive_retries(self.tcp_keepalive_retries))\n    }\n\n    /// Serve the service.\n    pub async fn serve<S, ResBody>(self, addr: SocketAddr, svc: S) -> Result<(), super::Error>\n    where\n        L: Layer<S>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send + 'static,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        let incoming = self.bind_incoming(addr)?;\n        self.serve_with_incoming(svc, incoming).await\n    }\n\n    /// Serve the service with the shutdown signal.\n    pub async fn serve_with_shutdown<S, F, ResBody>(\n        self,\n        addr: SocketAddr,\n        svc: S,\n        signal: F,\n    ) -> Result<(), super::Error>\n    where\n        L: Layer<S>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send + 'static,\n        F: Future<Output = ()>,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        let incoming = self.bind_incoming(addr)?;\n        self.serve_with_incoming_shutdown(svc, incoming, signal)\n            .await\n    }\n\n    /// Serve the service on the provided incoming stream.\n    ///\n    /// The `tcp_nodelay` and `tcp_keepalive` settings are ignored when using this method.\n    pub async fn serve_with_incoming<S, I, IO, IE, ResBody>(\n        self,\n        svc: S,\n        incoming: I,\n    ) -> Result<(), super::Error>\n    where\n        L: Layer<S>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send + 'static,\n        I: Stream<Item = Result<IO, IE>>,\n        IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,\n        IE: Into<crate::BoxError>,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        self.serve_internal(svc, incoming, Option::<future::Ready<()>>::None)\n            .await\n    }\n\n    /// Serve the service with the signal on the provided incoming stream.\n    pub async fn serve_with_incoming_shutdown<S, I, F, IO, IE, ResBody>(\n        self,\n        svc: S,\n        incoming: I,\n        signal: F,\n    ) -> Result<(), super::Error>\n    where\n        L: Layer<S>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send + 'static,\n        I: Stream<Item = Result<IO, IE>>,\n        IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,\n        IE: Into<crate::BoxError>,\n        F: Future<Output = ()>,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        self.serve_internal(svc, incoming, Some(signal)).await\n    }\n\n    async fn serve_internal<S, I, F, IO, IE, ResBody>(\n        self,\n        svc: S,\n        incoming: I,\n        signal: Option<F>,\n    ) -> Result<(), super::Error>\n    where\n        L: Layer<S>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<S>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send + 'static,\n        I: Stream<Item = Result<IO, IE>>,\n        IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,\n        IE: Into<crate::BoxError>,\n        F: Future<Output = ()>,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        let trace_interceptor = self.trace_interceptor.clone();\n        let concurrency_limit = self.concurrency_limit;\n        let load_shed = self.load_shed;\n        let init_connection_window_size = self.init_connection_window_size;\n        let init_stream_window_size = self.init_stream_window_size;\n        let max_concurrent_streams = self.max_concurrent_streams;\n        let timeout = self.timeout;\n        let max_header_list_size = self.http2_max_header_list_size;\n        let max_frame_size = self.max_frame_size;\n        let http2_only = !self.accept_http1;\n\n        let http2_keepalive_interval = self.http2_keepalive_interval;\n        let http2_keepalive_timeout = self.http2_keepalive_timeout;\n        let http2_adaptive_window = self.http2_adaptive_window;\n        let http2_max_pending_accept_reset_streams = self.http2_max_pending_accept_reset_streams;\n        let http2_max_local_error_reset_streams = self.http2_max_local_error_reset_streams;\n        let max_connection_age = self.max_connection_age;\n        let max_connection_age_grace = self.max_connection_age_grace;\n\n        let svc = self.service_builder.service(svc);\n\n        let incoming = io_stream::ServerIoStream::new(\n            incoming,\n            #[cfg(feature = \"_tls-any\")]\n            self.tls,\n        );\n        let mut svc = MakeSvc {\n            inner: svc,\n            concurrency_limit,\n            load_shed,\n            timeout,\n            trace_interceptor,\n            _io: PhantomData,\n        };\n\n        let server = {\n            let mut builder = ConnectionBuilder::new(TokioExecutor::new());\n\n            if http2_only {\n                builder = builder.http2_only();\n            }\n\n            builder\n                .http2()\n                .timer(TokioTimer::new())\n                .initial_connection_window_size(init_connection_window_size)\n                .initial_stream_window_size(init_stream_window_size)\n                .max_concurrent_streams(max_concurrent_streams)\n                .keep_alive_interval(http2_keepalive_interval)\n                .keep_alive_timeout(http2_keepalive_timeout)\n                .adaptive_window(http2_adaptive_window.unwrap_or_default())\n                .max_pending_accept_reset_streams(http2_max_pending_accept_reset_streams)\n                .max_local_error_reset_streams(http2_max_local_error_reset_streams)\n                .max_frame_size(max_frame_size);\n\n            if let Some(max_header_list_size) = max_header_list_size {\n                builder.http2().max_header_list_size(max_header_list_size);\n            }\n\n            builder\n        };\n\n        let (signal_tx, signal_rx) = tokio::sync::watch::channel(());\n        let signal_tx = Arc::new(signal_tx);\n\n        let graceful = signal.is_some();\n        let mut sig = pin!(Fuse { inner: signal });\n        let mut incoming = pin!(incoming);\n\n        loop {\n            tokio::select! {\n                _ = &mut sig => {\n                    trace!(\"signal received, shutting down\");\n                    break;\n                },\n                io = incoming.next() => {\n                    let io = match io {\n                        Some(Ok(io)) => io,\n                        Some(Err(e)) => {\n                            trace!(\"error accepting connection: {}\", DisplayErrorStack(&*e));\n                            continue;\n                        },\n                        None => {\n                            break\n                        },\n                    };\n\n                    trace!(\"connection accepted\");\n\n                    let req_svc = svc\n                        .call(&io)\n                        .await\n                        .map_err(super::Error::from_source)?;\n\n                    let hyper_io = TokioIo::new(io);\n                    let hyper_svc = TowerToHyperService::new(req_svc.map_request(|req: Request<Incoming>| req.map(Body::new)));\n\n                    serve_connection(hyper_io, hyper_svc, server.clone(), graceful.then(|| signal_rx.clone()), max_connection_age, max_connection_age_grace);\n                }\n            }\n        }\n\n        if graceful {\n            let _ = signal_tx.send(());\n            drop(signal_rx);\n            trace!(\n                \"waiting for {} connections to close\",\n                signal_tx.receiver_count()\n            );\n\n            // Wait for all connections to close\n            signal_tx.closed().await;\n        }\n\n        Ok(())\n    }\n}\n\nenum TimeoutAction {\n    GracefulShutdown,\n    ForcefulShutdown,\n}\n\nasync fn connection_timeout_future(\n    max_connection_age: Option<Duration>,\n    max_connection_age_grace: Option<Duration>,\n) -> TimeoutAction {\n    if let Some(age) = max_connection_age {\n        tokio::time::sleep(age).await;\n\n        if let Some(grace) = max_connection_age_grace {\n            tokio::time::sleep(grace).await;\n            TimeoutAction::ForcefulShutdown\n        } else {\n            TimeoutAction::GracefulShutdown\n        }\n    } else {\n        future::pending().await\n    }\n}\n\n// This is moved to its own function as a way to get around\n// https://github.com/rust-lang/rust/issues/102211\nfn serve_connection<B, IO, S, E>(\n    hyper_io: IO,\n    hyper_svc: S,\n    builder: ConnectionBuilder<E>,\n    mut watcher: Option<tokio::sync::watch::Receiver<()>>,\n    max_connection_age: Option<Duration>,\n    max_connection_age_grace: Option<Duration>,\n) where\n    B: http_body::Body + Send + 'static,\n    B::Data: Send,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>> + Send + Sync,\n    IO: hyper::rt::Read + hyper::rt::Write + Unpin + Send + 'static,\n    S: HyperService<Request<Incoming>, Response = Response<B>> + Clone + Send + 'static,\n    S::Future: Send + 'static,\n    S::Error: Into<Box<dyn std::error::Error + Send + Sync>> + Send,\n    E: HttpServerConnExec<S::Future, B> + Send + Sync + 'static,\n{\n    tokio::spawn(async move {\n        {\n            let mut sig = pin!(Fuse {\n                inner: watcher.as_mut().map(|w| w.changed()),\n            });\n\n            let mut conn = pin!(builder.serve_connection(hyper_io, hyper_svc));\n\n            let mut connection_timeout = pin!(connection_timeout_future(\n                max_connection_age,\n                max_connection_age_grace,\n            ));\n\n            loop {\n                tokio::select! {\n                    rv = &mut conn => {\n                        if let Err(err) = rv {\n                            debug!(\"failed serving connection: {}\", DisplayErrorStack(&*err));\n                        }\n                        break;\n                    },\n                    timeout_action = &mut connection_timeout => {\n                        match timeout_action {\n                            TimeoutAction::GracefulShutdown => {\n                                conn.as_mut().graceful_shutdown();\n                            },\n                            TimeoutAction::ForcefulShutdown => {\n                                debug!(\"forcefully closed connection\");\n                                break;\n                            }\n                        }\n                    },\n                    _ = &mut sig => {\n                        conn.as_mut().graceful_shutdown();\n                    },\n                }\n            }\n        }\n\n        drop(watcher);\n        trace!(\"connection closed\");\n    });\n}\n\n#[cfg(feature = \"router\")]\nimpl<L> Router<L> {\n    pub(crate) fn new(server: Server<L>, routes: Routes) -> Self {\n        Self { server, routes }\n    }\n}\n\n#[cfg(feature = \"router\")]\nimpl<L> Router<L> {\n    /// Add a new service to this router.\n    pub fn add_service<S>(mut self, svc: S) -> Self\n    where\n        S: Service<Request<Body>, Error = Infallible>\n            + NamedService\n            + Clone\n            + Send\n            + Sync\n            + 'static,\n        S::Response: axum::response::IntoResponse,\n        S::Future: Send + 'static,\n    {\n        self.routes = self.routes.add_service(svc);\n        self\n    }\n\n    /// Add a new optional service to this router.\n    ///\n    /// # Note\n    /// Even when the argument given is `None` this will capture *all* requests to this service name.\n    /// As a result, one cannot use this to toggle between two identically named implementations.\n    pub fn add_optional_service<S>(mut self, svc: Option<S>) -> Self\n    where\n        S: Service<Request<Body>, Error = Infallible>\n            + NamedService\n            + Clone\n            + Send\n            + Sync\n            + 'static,\n        S::Response: axum::response::IntoResponse,\n        S::Future: Send + 'static,\n    {\n        if let Some(svc) = svc {\n            self.routes = self.routes.add_service(svc);\n        }\n        self\n    }\n\n    /// Consume this [`Server`] creating a future that will execute the server\n    /// on [tokio]'s default executor.\n    ///\n    /// [`Server`]: struct.Server.html\n    /// [tokio]: https://docs.rs/tokio\n    pub async fn serve<ResBody>(self, addr: SocketAddr) -> Result<(), super::Error>\n    where\n        L: Layer<Routes> + Clone,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        self.server.serve(addr, self.routes.prepare()).await\n    }\n\n    /// Consume this [`Server`] creating a future that will execute the server\n    /// on [tokio]'s default executor. And shutdown when the provided signal\n    /// is received.\n    ///\n    /// [`Server`]: struct.Server.html\n    /// [tokio]: https://docs.rs/tokio\n    pub async fn serve_with_shutdown<F: Future<Output = ()>, ResBody>(\n        self,\n        addr: SocketAddr,\n        signal: F,\n    ) -> Result<(), super::Error>\n    where\n        L: Layer<Routes>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        self.server\n            .serve_with_shutdown(addr, self.routes.prepare(), signal)\n            .await\n    }\n\n    /// Consume this [`Server`] creating a future that will execute the server\n    /// on the provided incoming stream of `AsyncRead + AsyncWrite`.\n    ///\n    /// This method discards any provided [`Server`] TCP configuration.\n    ///\n    /// [`Server`]: struct.Server.html\n    pub async fn serve_with_incoming<I, IO, IE, ResBody>(\n        self,\n        incoming: I,\n    ) -> Result<(), super::Error>\n    where\n        I: Stream<Item = Result<IO, IE>>,\n        IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,\n        IE: Into<crate::BoxError>,\n        L: Layer<Routes>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        self.server\n            .serve_with_incoming(self.routes.prepare(), incoming)\n            .await\n    }\n\n    /// Consume this [`Server`] creating a future that will execute the server\n    /// on the provided incoming stream of `AsyncRead + AsyncWrite`. Similar to\n    /// `serve_with_shutdown` this method will also take a signal future to\n    /// gracefully shutdown the server.\n    ///\n    /// This method discards any provided [`Server`] TCP configuration.\n    ///\n    /// [`Server`]: struct.Server.html\n    pub async fn serve_with_incoming_shutdown<I, IO, IE, F, ResBody>(\n        self,\n        incoming: I,\n        signal: F,\n    ) -> Result<(), super::Error>\n    where\n        I: Stream<Item = Result<IO, IE>>,\n        IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,\n        IE: Into<crate::BoxError>,\n        F: Future<Output = ()>,\n        L: Layer<Routes>,\n        L::Service: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Future: Send,\n        <<L as Layer<Routes>>::Service as Service<Request<Body>>>::Error:\n            Into<crate::BoxError> + Send,\n        ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n        ResBody::Error: Into<crate::BoxError>,\n    {\n        self.server\n            .serve_with_incoming_shutdown(self.routes.prepare(), incoming, signal)\n            .await\n    }\n}\n\nimpl<L> fmt::Debug for Server<L> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Builder\").finish()\n    }\n}\n\n#[derive(Clone)]\nstruct Svc<S> {\n    inner: S,\n    trace_interceptor: Option<TraceInterceptor>,\n}\n\nimpl<S, ResBody> Service<Request<Body>> for Svc<S>\nwhere\n    S: Service<Request<Body>, Response = Response<ResBody>>,\n    S::Error: Into<crate::BoxError>,\n    ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n    ResBody::Error: Into<crate::BoxError>,\n{\n    type Response = Response<Body>;\n    type Error = crate::BoxError;\n    type Future = SvcFuture<S::Future>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, mut req: Request<Body>) -> Self::Future {\n        let span = if let Some(trace_interceptor) = &self.trace_interceptor {\n            let (parts, body) = req.into_parts();\n            let bodyless_request = Request::from_parts(parts, ());\n\n            let span = trace_interceptor(&bodyless_request);\n\n            let (parts, _) = bodyless_request.into_parts();\n            req = Request::from_parts(parts, body);\n\n            span\n        } else {\n            tracing::Span::none()\n        };\n\n        SvcFuture {\n            inner: self.inner.call(req),\n            span,\n        }\n    }\n}\n\n#[pin_project]\nstruct SvcFuture<F> {\n    #[pin]\n    inner: F,\n    span: tracing::Span,\n}\n\nimpl<F, E, ResBody> Future for SvcFuture<F>\nwhere\n    F: Future<Output = Result<Response<ResBody>, E>>,\n    E: Into<crate::BoxError>,\n    ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n    ResBody::Error: Into<crate::BoxError>,\n{\n    type Output = Result<Response<Body>, crate::BoxError>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this = self.project();\n        let _guard = this.span.enter();\n\n        let response: Response<ResBody> = ready!(this.inner.poll(cx)).map_err(Into::into)?;\n        let response = response.map(|body| Body::new(body.map_err(Into::into)));\n        Poll::Ready(Ok(response))\n    }\n}\n\nimpl<S> fmt::Debug for Svc<S> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Svc\").finish()\n    }\n}\n\n#[derive(Clone)]\nstruct MakeSvc<S, IO> {\n    concurrency_limit: Option<usize>,\n    load_shed: bool,\n    timeout: Option<Duration>,\n    inner: S,\n    trace_interceptor: Option<TraceInterceptor>,\n    _io: PhantomData<fn() -> IO>,\n}\n\nimpl<S, ResBody, IO> Service<&ServerIo<IO>> for MakeSvc<S, IO>\nwhere\n    IO: Connected + 'static,\n    S: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,\n    S::Future: Send,\n    S::Error: Into<crate::BoxError> + Send,\n    ResBody: http_body::Body<Data = Bytes> + Send + 'static,\n    ResBody::Error: Into<crate::BoxError>,\n{\n    type Response = BoxService;\n    type Error = crate::BoxError;\n    type Future = future::Ready<Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Ok(()).into()\n    }\n\n    fn call(&mut self, io: &ServerIo<IO>) -> Self::Future {\n        let conn_info = io.connect_info();\n\n        let svc = self.inner.clone();\n        let concurrency_limit = self.concurrency_limit;\n        let timeout = self.timeout;\n        let trace_interceptor = self.trace_interceptor.clone();\n\n        let svc = ServiceBuilder::new()\n            .layer(RecoverErrorLayer::new())\n            .option_layer(self.load_shed.then_some(LoadShedLayer::new()))\n            .option_layer(concurrency_limit.map(ConcurrencyLimitLayer::new))\n            .layer_fn(|s| GrpcTimeout::new(s, timeout))\n            .service(svc);\n\n        let svc = ServiceBuilder::new()\n            .layer(BoxCloneService::layer())\n            .layer(ConnectInfoLayer::new(conn_info.clone()))\n            .service(Svc {\n                inner: svc,\n                trace_interceptor,\n            });\n\n        future::ready(Ok(svc))\n    }\n}\n\n// From `futures-util` crate, borrowed since this is the only dependency tonic requires.\n// LICENSE: MIT or Apache-2.0\n// A future which only yields `Poll::Ready` once, and thereafter yields `Poll::Pending`.\n#[pin_project]\nstruct Fuse<F> {\n    #[pin]\n    inner: Option<F>,\n}\n\nimpl<F> Future for Fuse<F>\nwhere\n    F: Future,\n{\n    type Output = F::Output;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match self.as_mut().project().inner.as_pin_mut() {\n            Some(fut) => fut.poll(cx).map(|output| {\n                self.project().inner.set(None);\n                output\n            }),\n            None => Poll::Pending,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::transport::Server;\n    use std::time::Duration;\n\n    #[tokio::test(start_paused = true)]\n    async fn test_connection_timeout_no_max_age() {\n        let future = connection_timeout_future(None, None);\n\n        tokio::select! {\n            _ = future => {\n                panic!(\"timeout future should never complete when max_connection_age is None\");\n            }\n            _ = tokio::time::sleep(Duration::from_secs(1000)) => {\n            }\n        }\n    }\n\n    #[tokio::test(start_paused = true)]\n    async fn test_connection_timeout_with_max_connection_age() {\n        let future = connection_timeout_future(Some(Duration::from_secs(10)), None);\n\n        let action = future.await;\n        assert!(matches!(action, TimeoutAction::GracefulShutdown));\n    }\n\n    #[tokio::test(start_paused = true)]\n    async fn test_connection_timeout_with_max_connection_age_grace() {\n        let mut future = pin!(connection_timeout_future(\n            Some(Duration::from_secs(10)),\n            Some(Duration::from_secs(5)),\n        ));\n\n        tokio::select! {\n            _ = &mut future => {\n                panic!(\"should not complete before max_connection_age\");\n            }\n            _ = tokio::time::sleep(Duration::from_secs(9)) => {}\n        }\n\n        tokio::select! {\n            _ = &mut future => {\n                panic!(\"should not complete before max_connection_age_grace\");\n            }\n            _ = tokio::time::sleep(Duration::from_secs(4)) => {}\n        }\n\n        let action = future.await;\n        assert!(matches!(action, TimeoutAction::ForcefulShutdown));\n    }\n\n    #[test]\n    fn server_tcp_defaults() {\n        const EXAMPLE_TCP_KEEPALIVE: Duration = Duration::from_secs(10);\n        const EXAMPLE_TCP_KEEPALIVE_INTERVAL: Duration = Duration::from_secs(5);\n        const EXAMPLE_TCP_KEEPALIVE_RETRIES: u32 = 3;\n\n        // Using ::builder() or ::default() should do the same thing\n        let server_via_builder = Server::builder();\n        assert!(server_via_builder.tcp_nodelay);\n        assert_eq!(server_via_builder.tcp_keepalive, None);\n        assert_eq!(server_via_builder.tcp_keepalive_interval, None);\n        assert_eq!(server_via_builder.tcp_keepalive_retries, None);\n        let server_via_default = Server::default();\n        assert!(server_via_default.tcp_nodelay);\n        assert_eq!(server_via_default.tcp_keepalive, None);\n        assert_eq!(server_via_default.tcp_keepalive_interval, None);\n        assert_eq!(server_via_default.tcp_keepalive_retries, None);\n\n        // overriding should be possible\n        let server_via_builder = Server::builder()\n            .tcp_nodelay(false)\n            .tcp_keepalive(Some(EXAMPLE_TCP_KEEPALIVE))\n            .tcp_keepalive_interval(Some(EXAMPLE_TCP_KEEPALIVE_INTERVAL))\n            .tcp_keepalive_retries(Some(EXAMPLE_TCP_KEEPALIVE_RETRIES));\n        assert!(!server_via_builder.tcp_nodelay);\n        assert_eq!(\n            server_via_builder.tcp_keepalive,\n            Some(EXAMPLE_TCP_KEEPALIVE)\n        );\n        assert_eq!(\n            server_via_builder.tcp_keepalive_interval,\n            Some(EXAMPLE_TCP_KEEPALIVE_INTERVAL)\n        );\n        assert_eq!(\n            server_via_builder.tcp_keepalive_retries,\n            Some(EXAMPLE_TCP_KEEPALIVE_RETRIES)\n        );\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/server/service/io.rs",
    "content": "use crate::transport::server::Connected;\nuse std::io;\nuse std::io::IoSlice;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\nuse tokio::io::{AsyncRead, AsyncWrite, ReadBuf};\n#[cfg(feature = \"_tls-any\")]\nuse tokio_rustls::server::TlsStream;\nuse tower_layer::Layer;\nuse tower_service::Service;\n\n#[derive(Debug, Clone)]\npub(crate) struct ConnectInfoLayer<T> {\n    connect_info: T,\n}\n\nimpl<T> ConnectInfoLayer<T> {\n    pub(crate) fn new(connect_info: T) -> Self {\n        Self { connect_info }\n    }\n}\n\nimpl<S, T> Layer<S> for ConnectInfoLayer<T>\nwhere\n    T: Clone,\n{\n    type Service = ConnectInfo<S, T>;\n\n    fn layer(&self, inner: S) -> Self::Service {\n        ConnectInfo::new(inner, self.connect_info.clone())\n    }\n}\n\n#[derive(Debug, Clone)]\npub(crate) struct ConnectInfo<S, T> {\n    inner: S,\n    connect_info: T,\n}\n\nimpl<S, T> ConnectInfo<S, T> {\n    fn new(inner: S, connect_info: T) -> Self {\n        Self {\n            inner,\n            connect_info,\n        }\n    }\n}\n\nimpl<S, IO, ReqBody> Service<http::Request<ReqBody>> for ConnectInfo<S, ServerIoConnectInfo<IO>>\nwhere\n    S: Service<http::Request<ReqBody>>,\n    IO: Connected,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, mut req: http::Request<ReqBody>) -> Self::Future {\n        match self.connect_info.clone() {\n            ServerIoConnectInfo::Io(inner) => {\n                req.extensions_mut().insert(inner);\n            }\n            #[cfg(feature = \"_tls-any\")]\n            ServerIoConnectInfo::TlsIo(inner) => {\n                req.extensions_mut().insert(inner.get_ref().clone());\n                req.extensions_mut().insert(inner);\n            }\n        }\n        self.inner.call(req)\n    }\n}\n\npub(crate) enum ServerIo<IO> {\n    Io(IO),\n    #[cfg(feature = \"_tls-any\")]\n    TlsIo(Box<TlsStream<IO>>),\n}\n\npub(crate) enum ServerIoConnectInfo<IO: Connected> {\n    Io(<IO as Connected>::ConnectInfo),\n    #[cfg(feature = \"_tls-any\")]\n    TlsIo(<TlsStream<IO> as Connected>::ConnectInfo),\n}\n\nimpl<IO: Connected> Clone for ServerIoConnectInfo<IO> {\n    fn clone(&self) -> Self {\n        match self {\n            Self::Io(io) => Self::Io(io.clone()),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => Self::TlsIo(io.clone()),\n        }\n    }\n}\n\nimpl<IO> ServerIo<IO> {\n    pub(in crate::transport) fn new_io(io: IO) -> Self {\n        Self::Io(io)\n    }\n\n    #[cfg(feature = \"_tls-any\")]\n    pub(in crate::transport) fn new_tls_io(io: TlsStream<IO>) -> Self {\n        Self::TlsIo(Box::new(io))\n    }\n\n    pub(in crate::transport) fn connect_info(&self) -> ServerIoConnectInfo<IO>\n    where\n        IO: Connected,\n    {\n        match self {\n            Self::Io(io) => ServerIoConnectInfo::Io(io.connect_info()),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => ServerIoConnectInfo::TlsIo(io.connect_info()),\n        }\n    }\n}\n\nimpl<IO> AsyncRead for ServerIo<IO>\nwhere\n    IO: AsyncWrite + AsyncRead + Unpin,\n{\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &mut ReadBuf<'_>,\n    ) -> Poll<io::Result<()>> {\n        match &mut *self {\n            Self::Io(io) => Pin::new(io).poll_read(cx, buf),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => Pin::new(io).poll_read(cx, buf),\n        }\n    }\n}\n\nimpl<IO> AsyncWrite for ServerIo<IO>\nwhere\n    IO: AsyncWrite + AsyncRead + Unpin,\n{\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<io::Result<usize>> {\n        match &mut *self {\n            Self::Io(io) => Pin::new(io).poll_write(cx, buf),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => Pin::new(io).poll_write(cx, buf),\n        }\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        match &mut *self {\n            Self::Io(io) => Pin::new(io).poll_flush(cx),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => Pin::new(io).poll_flush(cx),\n        }\n    }\n\n    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        match &mut *self {\n            Self::Io(io) => Pin::new(io).poll_shutdown(cx),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => Pin::new(io).poll_shutdown(cx),\n        }\n    }\n\n    fn poll_write_vectored(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[IoSlice<'_>],\n    ) -> Poll<Result<usize, io::Error>> {\n        match &mut *self {\n            Self::Io(io) => Pin::new(io).poll_write_vectored(cx, bufs),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => Pin::new(io).poll_write_vectored(cx, bufs),\n        }\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        match self {\n            Self::Io(io) => io.is_write_vectored(),\n            #[cfg(feature = \"_tls-any\")]\n            Self::TlsIo(io) => io.is_write_vectored(),\n        }\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/server/service/mod.rs",
    "content": "mod io;\npub(crate) use self::io::{ConnectInfoLayer, ServerIo};\n\n#[cfg(feature = \"_tls-any\")]\nmod tls;\n#[cfg(feature = \"_tls-any\")]\npub(crate) use self::tls::TlsAcceptor;\n"
  },
  {
    "path": "tonic/src/transport/server/service/tls.rs",
    "content": "use std::{fmt, sync::Arc, time::Duration};\n\nuse tokio::io::{AsyncRead, AsyncWrite};\nuse tokio::time;\nuse tokio_rustls::{\n    TlsAcceptor as RustlsAcceptor,\n    rustls::{RootCertStore, ServerConfig, server::WebPkiClientVerifier},\n    server::TlsStream,\n};\n\nuse crate::transport::{\n    Certificate, Identity,\n    service::tls::{\n        ALPN_H2, TlsError, convert_certificate_to_pki_types, convert_identity_to_pki_types,\n    },\n};\n\n#[derive(Clone)]\npub(crate) struct TlsAcceptor {\n    inner: Arc<ServerConfig>,\n    timeout: Option<Duration>,\n}\n\nimpl TlsAcceptor {\n    pub(crate) fn new(\n        identity: &Identity,\n        client_ca_root: Option<&Certificate>,\n        client_auth_optional: bool,\n        ignore_client_order: bool,\n        use_key_log: bool,\n        timeout: Option<Duration>,\n    ) -> Result<Self, crate::BoxError> {\n        let builder = ServerConfig::builder();\n\n        let builder = match client_ca_root {\n            None => builder.with_no_client_auth(),\n            Some(cert) => {\n                let mut roots = RootCertStore::empty();\n                roots.add_parsable_certificates(convert_certificate_to_pki_types(cert)?);\n                let verifier = if client_auth_optional {\n                    WebPkiClientVerifier::builder(roots.into()).allow_unauthenticated()\n                } else {\n                    WebPkiClientVerifier::builder(roots.into())\n                }\n                .build()?;\n                builder.with_client_cert_verifier(verifier)\n            }\n        };\n\n        let (cert, key) = convert_identity_to_pki_types(identity)?;\n        let mut config = builder.with_single_cert(cert, key)?;\n        config.ignore_client_order = ignore_client_order;\n\n        if use_key_log {\n            config.key_log = Arc::new(tokio_rustls::rustls::KeyLogFile::new());\n        }\n\n        config.alpn_protocols.push(ALPN_H2.into());\n        Ok(Self {\n            inner: Arc::new(config),\n            timeout,\n        })\n    }\n\n    pub(crate) async fn accept<IO>(&self, io: IO) -> Result<TlsStream<IO>, crate::BoxError>\n    where\n        IO: AsyncRead + AsyncWrite + Unpin,\n    {\n        let acceptor = RustlsAcceptor::from(self.inner.clone());\n        let accept_fut = acceptor.accept(io);\n        match self.timeout {\n            Some(timeout) => time::timeout(timeout, accept_fut)\n                .await\n                .map_err(|_| TlsError::HandshakeTimeout)?,\n            None => accept_fut.await,\n        }\n        .map_err(Into::into)\n    }\n}\n\nimpl fmt::Debug for TlsAcceptor {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"TlsAcceptor\").finish()\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/server/tls.rs",
    "content": "use std::{fmt, time::Duration};\n\nuse super::service::TlsAcceptor;\nuse crate::transport::tls::{Certificate, Identity};\n\n/// Configures TLS settings for servers.\n#[derive(Clone, Default)]\npub struct ServerTlsConfig {\n    identity: Option<Identity>,\n    client_ca_root: Option<Certificate>,\n    client_auth_optional: bool,\n    ignore_client_order: bool,\n    use_key_log: bool,\n    timeout: Option<Duration>,\n}\n\nimpl fmt::Debug for ServerTlsConfig {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ServerTlsConfig\").finish()\n    }\n}\n\nimpl ServerTlsConfig {\n    /// Creates a new `ServerTlsConfig`.\n    pub fn new() -> Self {\n        ServerTlsConfig::default()\n    }\n\n    /// Sets the [`Identity`] of the server.\n    pub fn identity(self, identity: Identity) -> Self {\n        ServerTlsConfig {\n            identity: Some(identity),\n            ..self\n        }\n    }\n\n    /// Sets a certificate against which to validate client TLS certificates.\n    pub fn client_ca_root(self, cert: Certificate) -> Self {\n        ServerTlsConfig {\n            client_ca_root: Some(cert),\n            ..self\n        }\n    }\n\n    /// Sets whether client certificate verification is optional.\n    ///\n    /// This option has effect only if CA certificate is set.\n    ///\n    /// # Default\n    /// By default, this option is set to `false`.\n    pub fn client_auth_optional(self, optional: bool) -> Self {\n        ServerTlsConfig {\n            client_auth_optional: optional,\n            ..self\n        }\n    }\n\n    /// Sets whether the server's cipher preferences are followed instead of the client's.\n    ///\n    /// # Default\n    /// By default, this option is set to `false`.\n    pub fn ignore_client_order(self, ignore_client_order: bool) -> Self {\n        ServerTlsConfig {\n            ignore_client_order,\n            ..self\n        }\n    }\n\n    /// Use key log as specified by the `SSLKEYLOGFILE` environment variable.\n    pub fn use_key_log(self) -> Self {\n        ServerTlsConfig {\n            use_key_log: true,\n            ..self\n        }\n    }\n\n    /// Sets the timeout for the TLS handshake.\n    pub fn timeout(self, timeout: Duration) -> Self {\n        ServerTlsConfig {\n            timeout: Some(timeout),\n            ..self\n        }\n    }\n\n    pub(crate) fn tls_acceptor(&self) -> Result<TlsAcceptor, crate::BoxError> {\n        TlsAcceptor::new(\n            self.identity.as_ref().unwrap(),\n            self.client_ca_root.as_ref(),\n            self.client_auth_optional,\n            self.ignore_client_order,\n            self.use_key_log,\n            self.timeout,\n        )\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/server/unix.rs",
    "content": "use super::Connected;\nuse std::sync::Arc;\n\n/// Connection info for Unix domain socket streams.\n///\n/// This type will be accessible through [request extensions][ext] if you're using\n/// a unix stream.\n///\n/// See [Connected] for more details.\n///\n/// [ext]: crate::Request::extensions\n#[derive(Clone, Debug)]\npub struct UdsConnectInfo {\n    /// Peer address. This will be \"unnamed\" for client unix sockets.\n    pub peer_addr: Option<Arc<tokio::net::unix::SocketAddr>>,\n    /// Process credentials for the unix socket.\n    pub peer_cred: Option<tokio::net::unix::UCred>,\n}\n\nimpl Connected for tokio::net::UnixStream {\n    type ConnectInfo = UdsConnectInfo;\n\n    fn connect_info(&self) -> Self::ConnectInfo {\n        UdsConnectInfo {\n            peer_addr: self.peer_addr().ok().map(Arc::new),\n            peer_cred: self.peer_cred().ok(),\n        }\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/service/grpc_timeout.rs",
    "content": "use crate::{TimeoutExpired, metadata::GRPC_TIMEOUT_HEADER};\nuse http::{HeaderMap, HeaderValue, Request};\nuse pin_project::pin_project;\nuse std::{\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll, ready},\n    time::Duration,\n};\nuse tokio::time::Sleep;\nuse tower_service::Service;\n\n#[derive(Debug, Clone)]\npub(crate) struct GrpcTimeout<S> {\n    inner: S,\n    server_timeout: Option<Duration>,\n}\n\nimpl<S> GrpcTimeout<S> {\n    pub(crate) fn new(inner: S, server_timeout: Option<Duration>) -> Self {\n        Self {\n            inner,\n            server_timeout,\n        }\n    }\n}\n\nimpl<S, ReqBody> Service<Request<ReqBody>> for GrpcTimeout<S>\nwhere\n    S: Service<Request<ReqBody>>,\n    S::Error: Into<crate::BoxError>,\n{\n    type Response = S::Response;\n    type Error = crate::BoxError;\n    type Future = ResponseFuture<S::Future>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx).map_err(Into::into)\n    }\n\n    fn call(&mut self, req: Request<ReqBody>) -> Self::Future {\n        let client_timeout = try_parse_grpc_timeout(req.headers()).unwrap_or_else(|e| {\n            tracing::trace!(\"Error parsing `grpc-timeout` header {:?}\", e);\n            None\n        });\n\n        // Use the shorter of the two durations, if either are set\n        let timeout_duration = match (client_timeout, self.server_timeout) {\n            (None, None) => None,\n            (Some(dur), None) => Some(dur),\n            (None, Some(dur)) => Some(dur),\n            (Some(header), Some(server)) => {\n                let shorter_duration = std::cmp::min(header, server);\n                Some(shorter_duration)\n            }\n        };\n\n        ResponseFuture {\n            inner: self.inner.call(req),\n            sleep: timeout_duration.map(tokio::time::sleep),\n        }\n    }\n}\n\n#[pin_project]\npub(crate) struct ResponseFuture<F> {\n    #[pin]\n    inner: F,\n    #[pin]\n    sleep: Option<Sleep>,\n}\n\nimpl<F, Res, E> Future for ResponseFuture<F>\nwhere\n    F: Future<Output = Result<Res, E>>,\n    E: Into<crate::BoxError>,\n{\n    type Output = Result<Res, crate::BoxError>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this = self.project();\n\n        if let ready @ Poll::Ready(_) = this.inner.poll(cx) {\n            return ready.map_err(Into::into);\n        }\n\n        if let Some(sleep) = this.sleep.as_pin_mut() {\n            ready!(sleep.poll(cx));\n            return Poll::Ready(Err(TimeoutExpired(()).into()));\n        }\n\n        Poll::Pending\n    }\n}\n\nconst SECONDS_IN_HOUR: u64 = 60 * 60;\nconst SECONDS_IN_MINUTE: u64 = 60;\n\n/// Tries to parse the `grpc-timeout` header if it is present. If we fail to parse, returns\n/// the value we attempted to parse.\n///\n/// Follows the [gRPC over HTTP2 spec](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md).\nfn try_parse_grpc_timeout(\n    headers: &HeaderMap<HeaderValue>,\n) -> Result<Option<Duration>, &HeaderValue> {\n    let Some(val) = headers.get(GRPC_TIMEOUT_HEADER) else {\n        return Ok(None);\n    };\n\n    let (timeout_value, timeout_unit) = val\n        .to_str()\n        .map_err(|_| val)\n        .and_then(|s| if s.is_empty() { Err(val) } else { Ok(s) })?\n        // `HeaderValue::to_str` only returns `Ok` if the header contains ASCII so this\n        // `split_at` will never panic from trying to split in the middle of a character.\n        // See https://docs.rs/http/1/http/header/struct.HeaderValue.html#method.to_str\n        //\n        // `len - 1` also wont panic since we just checked `s.is_empty`.\n        .split_at(val.len() - 1);\n\n    // gRPC spec specifies `TimeoutValue` will be at most 8 digits\n    // Caping this at 8 digits also prevents integer overflow from ever occurring\n    if timeout_value.len() > 8 {\n        return Err(val);\n    }\n\n    let timeout_value: u64 = timeout_value.parse().map_err(|_| val)?;\n\n    let duration = match timeout_unit {\n        // Hours\n        \"H\" => Duration::from_secs(timeout_value * SECONDS_IN_HOUR),\n        // Minutes\n        \"M\" => Duration::from_secs(timeout_value * SECONDS_IN_MINUTE),\n        // Seconds\n        \"S\" => Duration::from_secs(timeout_value),\n        // Milliseconds\n        \"m\" => Duration::from_millis(timeout_value),\n        // Microseconds\n        \"u\" => Duration::from_micros(timeout_value),\n        // Nanoseconds\n        \"n\" => Duration::from_nanos(timeout_value),\n        _ => return Err(val),\n    };\n\n    Ok(Some(duration))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use quickcheck::{Arbitrary, Gen};\n    use quickcheck_macros::quickcheck;\n\n    // Helper function to reduce the boiler plate of our test cases\n    fn setup_map_try_parse(val: Option<&str>) -> Result<Option<Duration>, HeaderValue> {\n        let mut hm = HeaderMap::new();\n        if let Some(v) = val {\n            let hv = HeaderValue::from_str(v).unwrap();\n            hm.insert(GRPC_TIMEOUT_HEADER, hv);\n        };\n\n        try_parse_grpc_timeout(&hm).map_err(|e| e.clone())\n    }\n\n    #[test]\n    fn test_hours() {\n        let parsed_duration = setup_map_try_parse(Some(\"3H\")).unwrap().unwrap();\n        assert_eq!(Duration::from_secs(3 * 60 * 60), parsed_duration);\n    }\n\n    #[test]\n    fn test_minutes() {\n        let parsed_duration = setup_map_try_parse(Some(\"1M\")).unwrap().unwrap();\n        assert_eq!(Duration::from_secs(60), parsed_duration);\n    }\n\n    #[test]\n    fn test_seconds() {\n        let parsed_duration = setup_map_try_parse(Some(\"42S\")).unwrap().unwrap();\n        assert_eq!(Duration::from_secs(42), parsed_duration);\n    }\n\n    #[test]\n    fn test_milliseconds() {\n        let parsed_duration = setup_map_try_parse(Some(\"13m\")).unwrap().unwrap();\n        assert_eq!(Duration::from_millis(13), parsed_duration);\n    }\n\n    #[test]\n    fn test_microseconds() {\n        let parsed_duration = setup_map_try_parse(Some(\"2u\")).unwrap().unwrap();\n        assert_eq!(Duration::from_micros(2), parsed_duration);\n    }\n\n    #[test]\n    fn test_nanoseconds() {\n        let parsed_duration = setup_map_try_parse(Some(\"82n\")).unwrap().unwrap();\n        assert_eq!(Duration::from_nanos(82), parsed_duration);\n    }\n\n    #[test]\n    fn test_header_not_present() {\n        let parsed_duration = setup_map_try_parse(None).unwrap();\n        assert!(parsed_duration.is_none());\n    }\n\n    #[test]\n    #[should_panic(expected = \"82f\")]\n    fn test_invalid_unit() {\n        // \"f\" is not a valid TimeoutUnit\n        setup_map_try_parse(Some(\"82f\")).unwrap().unwrap();\n    }\n\n    #[test]\n    #[should_panic(expected = \"123456789H\")]\n    fn test_too_many_digits() {\n        // gRPC spec states TimeoutValue will be at most 8 digits\n        setup_map_try_parse(Some(\"123456789H\")).unwrap().unwrap();\n    }\n\n    #[test]\n    #[should_panic(expected = \"oneH\")]\n    fn test_invalid_digits() {\n        // gRPC spec states TimeoutValue will be at most 8 digits\n        setup_map_try_parse(Some(\"oneH\")).unwrap().unwrap();\n    }\n\n    #[quickcheck]\n    fn fuzz(header_value: HeaderValueGen) -> bool {\n        let header_value = header_value.0;\n\n        // this just shouldn't panic\n        let _ = setup_map_try_parse(Some(&header_value));\n\n        true\n    }\n\n    /// Newtype to implement `Arbitrary` for generating `String`s that are valid `HeaderValue`s.\n    #[derive(Clone, Debug)]\n    struct HeaderValueGen(String);\n\n    impl Arbitrary for HeaderValueGen {\n        fn arbitrary(g: &mut Gen) -> Self {\n            let max = g.choose(&(1..70).collect::<Vec<_>>()).copied().unwrap();\n            Self(gen_string(g, 0, max))\n        }\n    }\n\n    // copied from https://github.com/hyperium/http/blob/master/tests/header_map_fuzz.rs\n    fn gen_string(g: &mut Gen, min: usize, max: usize) -> String {\n        let bytes: Vec<_> = (min..max)\n            .map(|_| {\n                // Chars to pick from\n                g.choose(b\"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----\")\n                    .copied()\n                    .unwrap()\n            })\n            .collect();\n\n        String::from_utf8(bytes).unwrap()\n    }\n}\n"
  },
  {
    "path": "tonic/src/transport/service/mod.rs",
    "content": "pub(crate) mod grpc_timeout;\n#[cfg(feature = \"_tls-any\")]\npub(crate) mod tls;\n\npub(crate) use self::grpc_timeout::GrpcTimeout;\n"
  },
  {
    "path": "tonic/src/transport/service/tls.rs",
    "content": "use std::{fmt, io::Cursor};\n\nuse tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, pem::PemObject as _};\n\nuse crate::transport::{Certificate, Identity};\n\n/// h2 alpn in plain format for rustls.\npub(crate) const ALPN_H2: &[u8] = b\"h2\";\n\n#[derive(Debug)]\npub(crate) enum TlsError {\n    #[cfg(feature = \"channel\")]\n    H2NotNegotiated,\n    #[cfg(feature = \"tls-native-roots\")]\n    NativeCertsNotFound,\n    CertificateParseError,\n    PrivateKeyParseError,\n    HandshakeTimeout,\n}\n\nimpl fmt::Display for TlsError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            #[cfg(feature = \"channel\")]\n            TlsError::H2NotNegotiated => write!(f, \"HTTP/2 was not negotiated.\"),\n            #[cfg(feature = \"tls-native-roots\")]\n            TlsError::NativeCertsNotFound => write!(f, \"no native certs found\"),\n            TlsError::CertificateParseError => write!(f, \"Error parsing TLS certificate.\"),\n            TlsError::PrivateKeyParseError => write!(\n                f,\n                \"Error parsing TLS private key - no RSA or PKCS8-encoded keys found.\"\n            ),\n            TlsError::HandshakeTimeout => write!(f, \"TLS handshake timeout.\"),\n        }\n    }\n}\n\nimpl std::error::Error for TlsError {}\n\npub(crate) fn convert_certificate_to_pki_types(\n    certificate: &Certificate,\n) -> Result<Vec<CertificateDer<'static>>, TlsError> {\n    CertificateDer::pem_reader_iter(&mut Cursor::new(certificate))\n        .collect::<Result<Vec<_>, _>>()\n        .map_err(|_| TlsError::CertificateParseError)\n}\n\npub(crate) fn convert_identity_to_pki_types(\n    identity: &Identity,\n) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), TlsError> {\n    let cert = convert_certificate_to_pki_types(&identity.cert)?;\n    let key = PrivateKeyDer::from_pem_reader(&mut Cursor::new(&identity.key))\n        .map_err(|_| TlsError::PrivateKeyParseError)?;\n    Ok((cert, key))\n}\n"
  },
  {
    "path": "tonic/src/transport/tls.rs",
    "content": "/// Represents a X509 certificate.\n#[derive(Debug, Clone)]\npub struct Certificate {\n    pub(crate) pem: Vec<u8>,\n}\n\n/// Represents a private key and X509 certificate.\n#[derive(Debug, Clone)]\npub struct Identity {\n    pub(crate) cert: Certificate,\n    pub(crate) key: Vec<u8>,\n}\n\nimpl Certificate {\n    /// Parse a PEM encoded X509 Certificate.\n    ///\n    /// The provided PEM should include at least one PEM encoded certificate.\n    pub fn from_pem(pem: impl AsRef<[u8]>) -> Self {\n        let pem = pem.as_ref().into();\n        Self { pem }\n    }\n\n    /// Get a immutable reference to underlying certificate\n    pub fn get_ref(&self) -> &[u8] {\n        self.pem.as_slice()\n    }\n\n    /// Get a mutable reference to underlying certificate\n    pub fn get_mut(&mut self) -> &mut [u8] {\n        self.pem.as_mut()\n    }\n\n    /// Consumes `self`, returning the underlying certificate\n    pub fn into_inner(self) -> Vec<u8> {\n        self.pem\n    }\n}\n\nimpl AsRef<[u8]> for Certificate {\n    fn as_ref(&self) -> &[u8] {\n        self.pem.as_ref()\n    }\n}\n\nimpl AsMut<[u8]> for Certificate {\n    fn as_mut(&mut self) -> &mut [u8] {\n        self.pem.as_mut()\n    }\n}\n\nimpl Identity {\n    /// Parse a PEM encoded certificate and private key.\n    ///\n    /// The provided cert must contain at least one PEM encoded certificate.\n    pub fn from_pem(cert: impl AsRef<[u8]>, key: impl AsRef<[u8]>) -> Self {\n        let cert = Certificate::from_pem(cert);\n        let key = key.as_ref().into();\n        Self { cert, key }\n    }\n}\n"
  },
  {
    "path": "tonic/src/util.rs",
    "content": "//! Various utilities used throughout tonic.\n\n// some combinations of features might cause things here not to be used\n#![allow(dead_code)]\n\npub(crate) mod base64 {\n    use base64::{\n        alphabet,\n        engine::{\n            DecodePaddingMode,\n            general_purpose::{GeneralPurpose, GeneralPurposeConfig},\n        },\n    };\n\n    pub(crate) const STANDARD: GeneralPurpose = GeneralPurpose::new(\n        &alphabet::STANDARD,\n        GeneralPurposeConfig::new()\n            .with_encode_padding(true)\n            .with_decode_padding_mode(DecodePaddingMode::Indifferent),\n    );\n\n    pub(crate) const STANDARD_NO_PAD: GeneralPurpose = GeneralPurpose::new(\n        &alphabet::STANDARD,\n        GeneralPurposeConfig::new()\n            .with_encode_padding(false)\n            .with_decode_padding_mode(DecodePaddingMode::Indifferent),\n    );\n}\n"
  },
  {
    "path": "tonic-build/Cargo.toml",
    "content": "[package]\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\ncategories = [\"network-programming\", \"asynchronous\"]\ndescription = \"\"\"\nCodegen module of `tonic` gRPC implementation.\n\"\"\"\nedition = \"2024\"\nhomepage = \"https://github.com/hyperium/tonic\"\nkeywords = [\"rpc\", \"grpc\", \"async\", \"codegen\", \"protobuf\"]\nlicense = \"MIT\"\nname = \"tonic-build\"\nreadme = \"README.md\"\nrepository = \"https://github.com/hyperium/tonic\"\nversion = \"0.14.5\"\nrust-version = { workspace = true }\n\n[dependencies]\nprettyplease = { version = \"0.2\" }\nproc-macro2 = \"1.0\"\nquote = \"1.0\"\nsyn = \"2.0\"\n\n[features]\ndefault = [\"transport\"]\ntransport = []\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nall-features = true\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  # major released\n  \"proc_macro2::*\",\n]\n"
  },
  {
    "path": "tonic-build/README.md",
    "content": "# tonic-build\n\nProvides code generation for service stubs to use with tonic. For protobuf compilation via prost, use the `tonic-prost-build` crate instead.\n\n# Feature flags\n\n- `transport`: Enables generation of `connect` method using `tonic::transport::Channel`\n  (enabled by default).\n\n## Features\n\nRequired dependencies\n\n```toml\n[dependencies]\ntonic = \"<tonic-version>\"\nprost = \"<prost-version>\"\n\n[build-dependencies]\ntonic-prost-build = \"<tonic-version>\"\n```\n\n## Getting Started\n\nFor protobuf compilation, use `tonic-prost-build` in your [`build.rs` file](https://doc.rust-lang.org/cargo/reference/build-scripts.html) at the root of the binary/library.\n\nYou can rely on the defaults via\n\n```rust,no_run,ignore\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    tonic_prost_build::compile_protos(\"proto/service.proto\")?;\n    Ok(())\n}\n```\n\nOr configure the generated code deeper via\n\n```rust,no_run,ignore\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n   tonic_prost_build::configure()\n        .build_server(false)\n        .compile_protos(\n            &[\"proto/helloworld/helloworld.proto\"],\n            &[\"proto/helloworld\"],\n        )?;\n   Ok(())\n}\n```\n\nFor further details how to use the generated client/server, see the [examples here](https://github.com/hyperium/tonic/tree/master/examples) or the Google APIs example below.\n\n\n## NixOS related hints\n\nOn NixOS, it is better to specify the location of `PROTOC` and `PROTOC_INCLUDE` explicitly.\n\n```bash\n$ export PROTOBUF_LOCATION=$(nix-env -q protobuf --out-path --no-name)\n$ export PROTOC=$PROTOBUF_LOCATION/bin/protoc\n$ export PROTOC_INCLUDE=$PROTOBUF_LOCATION/include\n$ cargo build\n```\n\nThe reason being that if `prost_build::compile_protos` fails to generate the resultant package,\nthe failure is not obvious until the `include!(concat!(env!(\"OUT_DIR\"), \"/resultant.rs\"));`\nfails with `No such file or directory` error.\n\n### Google APIs example\nA good way to use Google API is probably using git submodules.\n\nSo suppose in our `proto` folder we do:\n```bash\ngit submodule add https://github.com/googleapis/googleapis\n\ngit submodule update --remote\n```\n\nAnd a bunch of Google proto files in structure will be like this:\n```raw\n├── googleapis\n│   └── google\n│       ├── api\n│       │   ├── annotations.proto\n│       │   ├── client.proto\n│       │   ├── field_behavior.proto\n│       │   ├── http.proto\n│       │   └── resource.proto\n│       └── pubsub\n│           └── v1\n│               ├── pubsub.proto\n│               └── schema.proto\n```\n\nThen we can generate Rust code via this setup in our `build.rs`:\n\n```rust,no_run,ignore\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    tonic_prost_build::configure()\n        .build_server(false)\n        //.out_dir(\"src/google\")  // you can change the generated code's location\n        .compile_protos(\n            &[\"proto/googleapis/google/pubsub/v1/pubsub.proto\"],\n            &[\"proto/googleapis\"], // specify the root location to search proto dependencies\n        )?;\n    Ok(())\n}\n```\n\nThen you can reference the generated Rust like this in your code:\n```rust,ignore\npub mod api {\n    tonic::include_proto!(\"google.pubsub.v1\");\n}\nuse api::{publisher_client::PublisherClient, ListTopicsRequest};\n```\n\nOr if you want to save the generated code in your own code base,\nyou can uncomment the line `.out_dir(...)` above, and in your lib file\nconfig a mod like this:\n```rust,ignore\npub mod google {\n    #[path = \"\"]\n    pub mod pubsub {\n        #[path = \"google.pubsub.v1.rs\"]\n        pub mod v1;\n    }\n}\n```\nSee [the example here](https://github.com/hyperium/tonic/tree/master/examples/src/gcp)\n"
  },
  {
    "path": "tonic-build/src/client.rs",
    "content": "use std::collections::HashSet;\n\nuse super::{Attributes, Method, Service};\nuse crate::{\n    format_method_name, format_method_path, format_service_name, generate_deprecated,\n    generate_doc_comments, naive_snake_case,\n};\nuse proc_macro2::TokenStream;\nuse quote::{format_ident, quote};\n\npub(crate) fn generate_internal<T: Service>(\n    service: &T,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    build_transport: bool,\n    attributes: &Attributes,\n    disable_comments: &HashSet<String>,\n) -> TokenStream {\n    let service_ident = quote::format_ident!(\"{}Client\", service.name());\n    let client_mod = quote::format_ident!(\"{}_client\", naive_snake_case(service.name()));\n    let methods = generate_methods(\n        service,\n        emit_package,\n        proto_path,\n        compile_well_known_types,\n        disable_comments,\n    );\n\n    let connect = generate_connect(&service_ident, build_transport);\n\n    let package = if emit_package { service.package() } else { \"\" };\n    let service_name = format_service_name(service, emit_package);\n\n    let service_doc = if disable_comments.contains(&service_name) {\n        TokenStream::new()\n    } else {\n        generate_doc_comments(service.comment())\n    };\n\n    let mod_attributes = attributes.for_mod(package);\n    let struct_attributes = attributes.for_struct(&service_name);\n\n    quote! {\n        /// Generated client implementations.\n        #(#mod_attributes)*\n        pub mod #client_mod {\n            #![allow(\n                unused_variables,\n                dead_code,\n                missing_docs,\n                clippy::wildcard_imports,\n                // will trigger if compression is disabled\n                clippy::let_unit_value,\n            )]\n            use tonic::codegen::*;\n            use tonic::codegen::http::Uri;\n\n            #service_doc\n            #(#struct_attributes)*\n            #[derive(Debug, Clone)]\n            pub struct #service_ident<T> {\n                inner: tonic::client::Grpc<T>,\n            }\n\n            #connect\n\n            impl<T> #service_ident<T>\n            where\n                T: tonic::client::GrpcService<tonic::body::Body>,\n                T::Error: Into<StdError>,\n                T::ResponseBody: Body<Data = Bytes> + std::marker::Send  + 'static,\n                <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,\n            {\n                pub fn new(inner: T) -> Self {\n                    let inner = tonic::client::Grpc::new(inner);\n                    Self { inner }\n                }\n\n                pub fn with_origin(inner: T, origin: Uri) -> Self {\n                    let inner = tonic::client::Grpc::with_origin(inner, origin);\n                    Self { inner }\n                }\n\n                pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>\n                where\n                    F: tonic::service::Interceptor,\n                    T::ResponseBody: Default,\n                    T: tonic::codegen::Service<\n                        http::Request<tonic::body::Body>,\n                        Response = http::Response<<T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody>\n                    >,\n                    <T as tonic::codegen::Service<http::Request<tonic::body::Body>>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,\n                {\n                    #service_ident::new(InterceptedService::new(inner, interceptor))\n                }\n\n                /// Compress requests with the given encoding.\n                ///\n                /// This requires the server to support it otherwise it might respond with an\n                /// error.\n                #[must_use]\n                pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n                    self.inner = self.inner.send_compressed(encoding);\n                    self\n                }\n\n                /// Enable decompressing responses.\n                #[must_use]\n                pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n                    self.inner = self.inner.accept_compressed(encoding);\n                    self\n                }\n\n                /// Limits the maximum size of a decoded message.\n                ///\n                /// Default: `4MB`\n                #[must_use]\n                pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n                    self.inner = self.inner.max_decoding_message_size(limit);\n                    self\n                }\n\n                /// Limits the maximum size of an encoded message.\n                ///\n                /// Default: `usize::MAX`\n                #[must_use]\n                pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n                    self.inner = self.inner.max_encoding_message_size(limit);\n                    self\n                }\n\n                #methods\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"transport\")]\nfn generate_connect(service_ident: &syn::Ident, enabled: bool) -> TokenStream {\n    let connect_impl = quote! {\n        impl #service_ident<tonic::transport::Channel> {\n            /// Attempt to create a new client by connecting to a given endpoint.\n            pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>\n            where\n                D: TryInto<tonic::transport::Endpoint>,\n                D::Error: Into<StdError>,\n            {\n                let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;\n                Ok(Self::new(conn))\n            }\n        }\n    };\n\n    if enabled {\n        connect_impl\n    } else {\n        TokenStream::new()\n    }\n}\n\n#[cfg(not(feature = \"transport\"))]\nfn generate_connect(_service_ident: &syn::Ident, _enabled: bool) -> TokenStream {\n    TokenStream::new()\n}\n\nfn generate_methods<T: Service>(\n    service: &T,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    disable_comments: &HashSet<String>,\n) -> TokenStream {\n    let mut stream = TokenStream::new();\n\n    for method in service.methods() {\n        if !disable_comments.contains(&format_method_name(service, method, emit_package)) {\n            stream.extend(generate_doc_comments(method.comment()));\n        }\n        if method.deprecated() {\n            stream.extend(generate_deprecated());\n        }\n\n        let method = match (method.client_streaming(), method.server_streaming()) {\n            (false, false) => generate_unary(\n                service,\n                method,\n                emit_package,\n                proto_path,\n                compile_well_known_types,\n            ),\n            (false, true) => generate_server_streaming(\n                service,\n                method,\n                emit_package,\n                proto_path,\n                compile_well_known_types,\n            ),\n            (true, false) => generate_client_streaming(\n                service,\n                method,\n                emit_package,\n                proto_path,\n                compile_well_known_types,\n            ),\n            (true, true) => generate_streaming(\n                service,\n                method,\n                emit_package,\n                proto_path,\n                compile_well_known_types,\n            ),\n        };\n\n        stream.extend(method);\n    }\n\n    stream\n}\n\nfn generate_unary<T: Service>(\n    service: &T,\n    method: &T::Method,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n) -> TokenStream {\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n    let ident = format_ident!(\"{}\", method.name());\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n    let service_name = format_service_name(service, emit_package);\n    let path = format_method_path(service, method, emit_package);\n    let method_name = method.identifier();\n\n    quote! {\n        pub async fn #ident(\n            &mut self,\n            request: impl tonic::IntoRequest<#request>,\n        ) -> std::result::Result<tonic::Response<#response>, tonic::Status> {\n           self.inner.ready().await.map_err(|e| {\n               tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n           })?;\n           let codec = #codec_name::default();\n           let path = http::uri::PathAndQuery::from_static(#path);\n           let mut req = request.into_request();\n           req.extensions_mut().insert(GrpcMethod::new(#service_name, #method_name));\n           self.inner.unary(req, path, codec).await\n        }\n    }\n}\n\nfn generate_server_streaming<T: Service>(\n    service: &T,\n    method: &T::Method,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n) -> TokenStream {\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n    let ident = format_ident!(\"{}\", method.name());\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n    let service_name = format_service_name(service, emit_package);\n    let path = format_method_path(service, method, emit_package);\n    let method_name = method.identifier();\n\n    quote! {\n        pub async fn #ident(\n            &mut self,\n            request: impl tonic::IntoRequest<#request>,\n        ) -> std::result::Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n            })?;\n            let codec = #codec_name::default();\n            let path = http::uri::PathAndQuery::from_static(#path);\n            let mut req = request.into_request();\n            req.extensions_mut().insert(GrpcMethod::new(#service_name, #method_name));\n            self.inner.server_streaming(req, path, codec).await\n        }\n    }\n}\n\nfn generate_client_streaming<T: Service>(\n    service: &T,\n    method: &T::Method,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n) -> TokenStream {\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n    let ident = format_ident!(\"{}\", method.name());\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n    let service_name = format_service_name(service, emit_package);\n    let path = format_method_path(service, method, emit_package);\n    let method_name = method.identifier();\n\n    quote! {\n        pub async fn #ident(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<Message = #request>\n        ) -> std::result::Result<tonic::Response<#response>, tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n            })?;\n            let codec = #codec_name::default();\n            let path = http::uri::PathAndQuery::from_static(#path);\n            let mut req = request.into_streaming_request();\n            req.extensions_mut().insert(GrpcMethod::new(#service_name, #method_name));\n            self.inner.client_streaming(req, path, codec).await\n        }\n    }\n}\n\nfn generate_streaming<T: Service>(\n    service: &T,\n    method: &T::Method,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n) -> TokenStream {\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n    let ident = format_ident!(\"{}\", method.name());\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n    let service_name = format_service_name(service, emit_package);\n    let path = format_method_path(service, method, emit_package);\n    let method_name = method.identifier();\n\n    quote! {\n        pub async fn #ident(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<Message = #request>\n        ) -> std::result::Result<tonic::Response<tonic::codec::Streaming<#response>>, tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n            })?;\n            let codec = #codec_name::default();\n            let path = http::uri::PathAndQuery::from_static(#path);\n            let mut req = request.into_streaming_request();\n            req.extensions_mut().insert(GrpcMethod::new(#service_name,#method_name));\n            self.inner.streaming(req, path, codec).await\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-build/src/code_gen.rs",
    "content": "//! Generic code generation for gRPC services.\n//!\n//! This module provides the generic infrastructure for generating\n//! client and server code from service definitions.\n\nuse std::collections::HashSet;\n\nuse proc_macro2::TokenStream;\n\nuse crate::{Attributes, Service};\n\n/// Builder for the generic code generation of server and clients.\n#[derive(Debug)]\npub struct CodeGenBuilder {\n    emit_package: bool,\n    compile_well_known_types: bool,\n    attributes: Attributes,\n    build_transport: bool,\n    disable_comments: HashSet<String>,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n}\n\nimpl CodeGenBuilder {\n    /// Create a new code gen builder with default options.\n    pub fn new() -> Self {\n        Default::default()\n    }\n\n    /// Enable code generation to emit the package name.\n    pub fn emit_package(&mut self, enable: bool) -> &mut Self {\n        self.emit_package = enable;\n        self\n    }\n\n    /// Attributes that will be added to `mod` and `struct` items.\n    ///\n    /// Reference [`Attributes`] for more information.\n    pub fn attributes(&mut self, attributes: Attributes) -> &mut Self {\n        self.attributes = attributes;\n        self\n    }\n\n    /// Enable transport code to be generated, this requires `tonic`'s `transport`\n    /// feature.\n    ///\n    /// This allows codegen level control of generating the transport code and\n    /// is a work around when other crates in a workspace enable this feature.\n    pub fn build_transport(&mut self, build_transport: bool) -> &mut Self {\n        self.build_transport = build_transport;\n        self\n    }\n\n    /// Enable compiling well known types, this will force codegen to not\n    /// use the well known types from `prost-types`.\n    pub fn compile_well_known_types(&mut self, enable: bool) -> &mut Self {\n        self.compile_well_known_types = enable;\n        self\n    }\n\n    /// Disable comments based on a proto path.\n    pub fn disable_comments(&mut self, disable_comments: HashSet<String>) -> &mut Self {\n        self.disable_comments = disable_comments;\n        self\n    }\n\n    /// Emit `Arc<Self>` instead of `&self` in service trait.\n    pub fn use_arc_self(&mut self, enable: bool) -> &mut Self {\n        self.use_arc_self = enable;\n        self\n    }\n\n    /// Enable or disable returning automatic unimplemented gRPC error code for generated traits.\n    pub fn generate_default_stubs(&mut self, generate_default_stubs: bool) -> &mut Self {\n        self.generate_default_stubs = generate_default_stubs;\n        self\n    }\n\n    /// Generate client code based on `Service`.\n    ///\n    /// This takes some `Service` and will generate a `TokenStream` that contains\n    /// a public module with the generated client.\n    pub fn generate_client(&self, service: &impl Service, proto_path: &str) -> TokenStream {\n        crate::client::generate_internal(\n            service,\n            self.emit_package,\n            proto_path,\n            self.compile_well_known_types,\n            self.build_transport,\n            &self.attributes,\n            &self.disable_comments,\n        )\n    }\n\n    /// Generate server code based on `Service`.\n    ///\n    /// This takes some `Service` and will generate a `TokenStream` that contains\n    /// a public module with the generated client.\n    pub fn generate_server(&self, service: &impl Service, proto_path: &str) -> TokenStream {\n        crate::server::generate_internal(\n            service,\n            self.emit_package,\n            proto_path,\n            self.compile_well_known_types,\n            &self.attributes,\n            &self.disable_comments,\n            self.use_arc_self,\n            self.generate_default_stubs,\n        )\n    }\n}\n\nimpl Default for CodeGenBuilder {\n    fn default() -> Self {\n        Self {\n            emit_package: true,\n            compile_well_known_types: false,\n            attributes: Attributes::default(),\n            build_transport: true,\n            disable_comments: HashSet::default(),\n            use_arc_self: false,\n            generate_default_stubs: false,\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-build/src/lib.rs",
    "content": "#![doc = include_str!(\"../README.md\")]\n#![recursion_limit = \"256\"]\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg\"\n)]\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nuse proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream};\nuse quote::TokenStreamExt;\n\n// Prost functionality has been moved to tonic-prost-build\n\npub mod manual;\n\n/// Service code generation for client\nmod client;\n/// Service code generation for Server\nmod server;\n\nmod code_gen;\npub use code_gen::CodeGenBuilder;\n\n/// Service generation trait.\n///\n/// This trait can be implemented and consumed\n/// by `client::generate` and `server::generate`\n/// to allow any codegen module to generate service\n/// abstractions.\npub trait Service {\n    /// Comment type.\n    type Comment: AsRef<str>;\n\n    /// Method type.\n    type Method: Method;\n\n    /// Name of service.\n    fn name(&self) -> &str;\n    /// Package name of service.\n    fn package(&self) -> &str;\n    /// Identifier used to generate type name.\n    fn identifier(&self) -> &str;\n    /// Methods provided by service.\n    fn methods(&self) -> &[Self::Method];\n    /// Get comments about this item.\n    fn comment(&self) -> &[Self::Comment];\n}\n\n/// Method generation trait.\n///\n/// Each service contains a set of generic\n/// `Methods`'s that will be used by codegen\n/// to generate abstraction implementations for\n/// the provided methods.\npub trait Method {\n    /// Comment type.\n    type Comment: AsRef<str>;\n\n    /// Name of method.\n    fn name(&self) -> &str;\n    /// Identifier used to generate type name.\n    fn identifier(&self) -> &str;\n    /// Path to the codec.\n    fn codec_path(&self) -> &str;\n    /// Method is streamed by client.\n    fn client_streaming(&self) -> bool;\n    /// Method is streamed by server.\n    fn server_streaming(&self) -> bool;\n    /// Get comments about this item.\n    fn comment(&self) -> &[Self::Comment];\n    /// Method is deprecated.\n    fn deprecated(&self) -> bool {\n        false\n    }\n    /// Type name of request and response.\n    fn request_response_name(\n        &self,\n        proto_path: &str,\n        compile_well_known_types: bool,\n    ) -> (TokenStream, TokenStream);\n}\n\n/// Attributes that will be added to `mod` and `struct` items.\n#[derive(Debug, Default, Clone)]\npub struct Attributes {\n    /// `mod` attributes.\n    module: Vec<(String, String)>,\n    /// `struct` attributes.\n    structure: Vec<(String, String)>,\n    /// `trait` attributes.\n    trait_attributes: Vec<(String, String)>,\n}\n\nimpl Attributes {\n    fn for_mod(&self, name: &str) -> Vec<syn::Attribute> {\n        generate_attributes(name, &self.module)\n    }\n\n    fn for_struct(&self, name: &str) -> Vec<syn::Attribute> {\n        generate_attributes(name, &self.structure)\n    }\n\n    fn for_trait(&self, name: &str) -> Vec<syn::Attribute> {\n        generate_attributes(name, &self.trait_attributes)\n    }\n\n    /// Add an attribute that will be added to `mod` items matching the given pattern.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic_build::*;\n    /// let mut attributes = Attributes::default();\n    /// attributes.push_mod(\"my.proto.package\", r#\"#[cfg(feature = \"server\")]\"#);\n    /// ```\n    pub fn push_mod(&mut self, pattern: impl Into<String>, attr: impl Into<String>) {\n        self.module.push((pattern.into(), attr.into()));\n    }\n\n    /// Add an attribute that will be added to `struct` items matching the given pattern.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic_build::*;\n    /// let mut attributes = Attributes::default();\n    /// attributes.push_struct(\"EchoService\", \"#[derive(PartialEq)]\");\n    /// ```\n    pub fn push_struct(&mut self, pattern: impl Into<String>, attr: impl Into<String>) {\n        self.structure.push((pattern.into(), attr.into()));\n    }\n\n    /// Add an attribute that will be added to `trait` items matching the given pattern.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tonic_build::*;\n    /// let mut attributes = Attributes::default();\n    /// attributes.push_trait(\"Server\", \"#[mockall::automock]\");\n    /// ```\n    pub fn push_trait(&mut self, pattern: impl Into<String>, attr: impl Into<String>) {\n        self.trait_attributes.push((pattern.into(), attr.into()));\n    }\n}\n\nfn format_service_name<T: Service>(service: &T, emit_package: bool) -> String {\n    let package = if emit_package { service.package() } else { \"\" };\n    format!(\n        \"{}{}{}\",\n        package,\n        if package.is_empty() { \"\" } else { \".\" },\n        service.identifier(),\n    )\n}\n\nfn format_method_path<T: Service>(service: &T, method: &T::Method, emit_package: bool) -> String {\n    format!(\n        \"/{}/{}\",\n        format_service_name(service, emit_package),\n        method.identifier()\n    )\n}\n\nfn format_method_name<T: Service>(service: &T, method: &T::Method, emit_package: bool) -> String {\n    format!(\n        \"{}.{}\",\n        format_service_name(service, emit_package),\n        method.identifier()\n    )\n}\n\n// Generates attributes given a list of (`pattern`, `attribute`) pairs. If `pattern` matches `name`, `attribute` will be included.\nfn generate_attributes<'a>(\n    name: &str,\n    attrs: impl IntoIterator<Item = &'a (String, String)>,\n) -> Vec<syn::Attribute> {\n    attrs\n        .into_iter()\n        .filter(|(matcher, _)| match_name(matcher, name))\n        .flat_map(|(_, attr)| {\n            // attributes cannot be parsed directly, so we pretend they're on a struct\n            syn::parse_str::<syn::DeriveInput>(&format!(\"{attr}\\nstruct fake;\"))\n                .unwrap()\n                .attrs\n        })\n        .collect::<Vec<_>>()\n}\n\nfn generate_deprecated() -> TokenStream {\n    let mut deprecated_stream = TokenStream::new();\n    deprecated_stream.append(Ident::new(\"deprecated\", Span::call_site()));\n\n    let group = Group::new(Delimiter::Bracket, deprecated_stream);\n\n    let mut stream = TokenStream::new();\n    stream.append(Punct::new('#', Spacing::Alone));\n    stream.append(group);\n\n    stream\n}\n\n// Generate a singular line of a doc comment\nfn generate_doc_comment<S: AsRef<str>>(comment: S) -> TokenStream {\n    let comment = comment.as_ref();\n\n    let comment = if !comment.starts_with(' ') {\n        format!(\" {comment}\")\n    } else {\n        comment.to_string()\n    };\n\n    let mut doc_stream = TokenStream::new();\n\n    doc_stream.append(Ident::new(\"doc\", Span::call_site()));\n    doc_stream.append(Punct::new('=', Spacing::Alone));\n    doc_stream.append(Literal::string(comment.as_ref()));\n\n    let group = Group::new(Delimiter::Bracket, doc_stream);\n\n    let mut stream = TokenStream::new();\n    stream.append(Punct::new('#', Spacing::Alone));\n    stream.append(group);\n    stream\n}\n\n// Generate a larger doc comment composed of many lines of doc comments\nfn generate_doc_comments<T: AsRef<str>>(comments: &[T]) -> TokenStream {\n    let mut stream = TokenStream::new();\n\n    for comment in comments {\n        stream.extend(generate_doc_comment(comment));\n    }\n\n    stream\n}\n\n// Checks whether a path pattern matches a given path.\npub(crate) fn match_name(pattern: &str, path: &str) -> bool {\n    if pattern.is_empty() {\n        false\n    } else if pattern == \".\" || pattern == path {\n        true\n    } else {\n        let pattern_segments = pattern.split('.').collect::<Vec<_>>();\n        let path_segments = path.split('.').collect::<Vec<_>>();\n\n        if &pattern[..1] == \".\" {\n            // prefix match\n            if pattern_segments.len() > path_segments.len() {\n                false\n            } else {\n                pattern_segments[..] == path_segments[..pattern_segments.len()]\n            }\n        // suffix match\n        } else if pattern_segments.len() > path_segments.len() {\n            false\n        } else {\n            pattern_segments[..] == path_segments[path_segments.len() - pattern_segments.len()..]\n        }\n    }\n}\n\nfn naive_snake_case(name: &str) -> String {\n    let mut s = String::new();\n    let mut it = name.chars().peekable();\n\n    while let Some(x) = it.next() {\n        s.push(x.to_ascii_lowercase());\n        if let Some(y) = it.peek() {\n            if y.is_uppercase() {\n                s.push('_');\n            }\n        }\n    }\n\n    s\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_match_name() {\n        assert!(match_name(\".\", \".my.protos\"));\n        assert!(match_name(\".\", \".protos\"));\n\n        assert!(match_name(\".my\", \".my\"));\n        assert!(match_name(\".my\", \".my.protos\"));\n        assert!(match_name(\".my.protos.Service\", \".my.protos.Service\"));\n\n        assert!(match_name(\"Service\", \".my.protos.Service\"));\n\n        assert!(!match_name(\".m\", \".my.protos\"));\n        assert!(!match_name(\".p\", \".protos\"));\n\n        assert!(!match_name(\".my\", \".myy\"));\n        assert!(!match_name(\".protos\", \".my.protos\"));\n        assert!(!match_name(\".Service\", \".my.protos.Service\"));\n\n        assert!(!match_name(\"service\", \".my.protos.Service\"));\n    }\n\n    #[test]\n    fn test_snake_case() {\n        for case in &[\n            (\"Service\", \"service\"),\n            (\"ThatHasALongName\", \"that_has_a_long_name\"),\n            (\"greeter\", \"greeter\"),\n            (\"ABCServiceX\", \"a_b_c_service_x\"),\n        ] {\n            assert_eq!(naive_snake_case(case.0), case.1)\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-build/src/manual.rs",
    "content": "//! This module provides utilities for generating `tonic` service stubs and clients\n//! purely in Rust without the need of `proto` files. It also enables you to set a custom `Codec`\n//! if you want to use a custom serialization format other than `protobuf`.\n//!\n//! # Example\n//!\n//! ```rust,no_run\n//! fn main() -> Result<(), Box<dyn std::error::Error>> {\n//!     let greeter_service = tonic_build::manual::Service::builder()\n//!         .name(\"Greeter\")\n//!         .package(\"helloworld\")\n//!         .method(\n//!             tonic_build::manual::Method::builder()\n//!                 .name(\"say_hello\")\n//!                 .route_name(\"SayHello\")\n//!                 // Provide the path to the Request type\n//!                 .input_type(\"crate::HelloRequest\")\n//!                 // Provide the path to the Response type\n//!                 .output_type(\"super::HelloResponse\")\n//!                 // Provide the path to the Codec to use\n//!                 .codec_path(\"crate::JsonCodec\")\n//!                 .build(),\n//!         )\n//!         .build();\n//!\n//!     tonic_build::manual::Builder::new().compile(&[greeter_service]);\n//!     Ok(())\n//! }\n//! ```\n\nuse crate::code_gen::CodeGenBuilder;\n\nuse proc_macro2::TokenStream;\nuse quote::ToTokens;\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n};\n\n/// Service builder.\n///\n/// This builder can be used to manually define a gRPC service in rust code without the use of a\n/// .proto file.\n///\n/// # Example\n///\n/// ```\n/// # use tonic_build::manual::Service;\n/// let greeter_service = Service::builder()\n///     .name(\"Greeter\")\n///     .package(\"helloworld\")\n///     // Add various methods to the service\n///     // .method()\n///     .build();\n/// ```\n#[derive(Debug, Default)]\npub struct ServiceBuilder {\n    /// The service name in Rust style.\n    name: Option<String>,\n    /// The package name as it appears in the .proto file.\n    package: Option<String>,\n    /// The service comments.\n    comments: Vec<String>,\n    /// The service methods.\n    methods: Vec<Method>,\n}\n\nimpl ServiceBuilder {\n    /// Set the name for this Service.\n    ///\n    /// This value will be used both as the base for the generated rust types and service trait as\n    /// well as part of the route for calling this service. Routes have the form:\n    /// `/<package_name>.<service_name>/<method_route_name>`\n    pub fn name(mut self, name: impl AsRef<str>) -> Self {\n        self.name = Some(name.as_ref().to_owned());\n        self\n    }\n\n    /// Set the package this Service is part of.\n    ///\n    /// This value will be used as part of the route for calling this service.\n    /// Routes have the form: `/<package_name>.<service_name>/<method_route_name>`\n    pub fn package(mut self, package: impl AsRef<str>) -> Self {\n        self.package = Some(package.as_ref().to_owned());\n        self\n    }\n\n    /// Add a comment string that should be included as a doc comment for this Service.\n    pub fn comment(mut self, comment: impl AsRef<str>) -> Self {\n        self.comments.push(comment.as_ref().to_owned());\n        self\n    }\n\n    /// Adds a Method to this Service.\n    pub fn method(mut self, method: Method) -> Self {\n        self.methods.push(method);\n        self\n    }\n\n    /// Build a Service.\n    ///\n    /// Panics if `name` or `package` weren't set.\n    pub fn build(self) -> Service {\n        Service {\n            name: self.name.unwrap(),\n            comments: self.comments,\n            package: self.package.unwrap(),\n            methods: self.methods,\n        }\n    }\n}\n\n/// A service descriptor.\n#[derive(Debug)]\npub struct Service {\n    /// The service name in Rust style.\n    name: String,\n    /// The package name as it appears in the .proto file.\n    package: String,\n    /// The service comments.\n    comments: Vec<String>,\n    /// The service methods.\n    methods: Vec<Method>,\n}\n\nimpl Service {\n    /// Create a new `ServiceBuilder`\n    pub fn builder() -> ServiceBuilder {\n        ServiceBuilder::default()\n    }\n}\n\nimpl crate::Service for Service {\n    type Comment = String;\n\n    type Method = Method;\n\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn package(&self) -> &str {\n        &self.package\n    }\n\n    fn identifier(&self) -> &str {\n        &self.name\n    }\n\n    fn methods(&self) -> &[Self::Method] {\n        &self.methods\n    }\n\n    fn comment(&self) -> &[Self::Comment] {\n        &self.comments\n    }\n}\n\n/// A service method descriptor.\n#[derive(Debug)]\npub struct Method {\n    /// The name of the method in Rust style.\n    name: String,\n    /// The name of the method as should be used when constructing a route\n    route_name: String,\n    /// The method comments.\n    comments: Vec<String>,\n    /// The input Rust type.\n    input_type: String,\n    /// The output Rust type.\n    output_type: String,\n    /// Identifies if client streams multiple client messages.\n    client_streaming: bool,\n    /// Identifies if server streams multiple server messages.\n    server_streaming: bool,\n    /// Identifies if the method is deprecated.\n    deprecated: bool,\n    /// The path to the codec to use for this method\n    codec_path: String,\n}\n\nimpl Method {\n    /// Create a new `MethodBuilder`\n    pub fn builder() -> MethodBuilder {\n        MethodBuilder::default()\n    }\n}\n\nimpl crate::Method for Method {\n    type Comment = String;\n\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn identifier(&self) -> &str {\n        &self.route_name\n    }\n\n    fn codec_path(&self) -> &str {\n        &self.codec_path\n    }\n\n    fn client_streaming(&self) -> bool {\n        self.client_streaming\n    }\n\n    fn server_streaming(&self) -> bool {\n        self.server_streaming\n    }\n\n    fn comment(&self) -> &[Self::Comment] {\n        &self.comments\n    }\n\n    fn deprecated(&self) -> bool {\n        self.deprecated\n    }\n\n    fn request_response_name(\n        &self,\n        _proto_path: &str,\n        _compile_well_known_types: bool,\n    ) -> (TokenStream, TokenStream) {\n        let request = syn::parse_str::<syn::Path>(&self.input_type)\n            .unwrap()\n            .to_token_stream();\n        let response = syn::parse_str::<syn::Path>(&self.output_type)\n            .unwrap()\n            .to_token_stream();\n        (request, response)\n    }\n}\n\n/// Method builder.\n///\n/// This builder can be used to manually define gRPC method, which can be added to a gRPC service,\n/// in rust code without the use of a .proto file.\n///\n/// # Example\n///\n/// ```\n/// # use tonic_build::manual::Method;\n/// let say_hello_method = Method::builder()\n///     .name(\"say_hello\")\n///     .route_name(\"SayHello\")\n///     // Provide the path to the Request type\n///     .input_type(\"crate::common::HelloRequest\")\n///     // Provide the path to the Response type\n///     .output_type(\"crate::common::HelloResponse\")\n///     // Provide the path to the Codec to use\n///     .codec_path(\"crate::common::JsonCodec\")\n///     .build();\n/// ```\n#[derive(Debug, Default)]\npub struct MethodBuilder {\n    /// The name of the method in Rust style.\n    name: Option<String>,\n    /// The name of the method as should be used when constructing a route\n    route_name: Option<String>,\n    /// The method comments.\n    comments: Vec<String>,\n    /// The input Rust type.\n    input_type: Option<String>,\n    /// The output Rust type.\n    output_type: Option<String>,\n    /// Identifies if client streams multiple client messages.\n    client_streaming: bool,\n    /// Identifies if server streams multiple server messages.\n    server_streaming: bool,\n    /// Identifies if the method is deprecated.\n    deprecated: bool,\n    /// The path to the codec to use for this method\n    codec_path: Option<String>,\n}\n\nimpl MethodBuilder {\n    /// Set the name for this Method.\n    ///\n    /// This value will be used for generating the client functions for calling this Method.\n    ///\n    /// Generally this is formatted in snake_case.\n    pub fn name(mut self, name: impl AsRef<str>) -> Self {\n        self.name = Some(name.as_ref().to_owned());\n        self\n    }\n\n    /// Set the route_name for this Method.\n    ///\n    /// This value will be used as part of the route for calling this method.\n    /// Routes have the form: `/<package_name>.<service_name>/<method_route_name>`\n    ///\n    /// Generally this is formatted in PascalCase.\n    pub fn route_name(mut self, route_name: impl AsRef<str>) -> Self {\n        self.route_name = Some(route_name.as_ref().to_owned());\n        self\n    }\n\n    /// Add a comment string that should be included as a doc comment for this Method.\n    pub fn comment(mut self, comment: impl AsRef<str>) -> Self {\n        self.comments.push(comment.as_ref().to_owned());\n        self\n    }\n\n    /// Set the path to the Rust type that should be use for the Request type of this method.\n    pub fn input_type(mut self, input_type: impl AsRef<str>) -> Self {\n        self.input_type = Some(input_type.as_ref().to_owned());\n        self\n    }\n\n    /// Set the path to the Rust type that should be use for the Response type of this method.\n    pub fn output_type(mut self, output_type: impl AsRef<str>) -> Self {\n        self.output_type = Some(output_type.as_ref().to_owned());\n        self\n    }\n\n    /// Set the path to the Rust type that should be used as the `Codec` for this method.\n    ///\n    /// Currently the codegen assumes that this type implements `Default`.\n    pub fn codec_path(mut self, codec_path: impl AsRef<str>) -> Self {\n        self.codec_path = Some(codec_path.as_ref().to_owned());\n        self\n    }\n\n    /// Sets if the Method request from the client is streamed.\n    pub fn client_streaming(mut self) -> Self {\n        self.client_streaming = true;\n        self\n    }\n\n    /// Sets if the Method response from the server is streamed.\n    pub fn server_streaming(mut self) -> Self {\n        self.server_streaming = true;\n        self\n    }\n\n    /// Build a Method\n    ///\n    /// Panics if `name`, `route_name`, `input_type`, `output_type`, or `codec_path` weren't set.\n    pub fn build(self) -> Method {\n        Method {\n            name: self.name.unwrap(),\n            route_name: self.route_name.unwrap(),\n            comments: self.comments,\n            input_type: self.input_type.unwrap(),\n            output_type: self.output_type.unwrap(),\n            client_streaming: self.client_streaming,\n            server_streaming: self.server_streaming,\n            deprecated: self.deprecated,\n            codec_path: self.codec_path.unwrap(),\n        }\n    }\n}\n\nstruct ServiceGenerator {\n    builder: Builder,\n    clients: TokenStream,\n    servers: TokenStream,\n}\n\nimpl ServiceGenerator {\n    fn generate(&mut self, service: &Service) {\n        if self.builder.build_server {\n            let server = CodeGenBuilder::new()\n                .emit_package(true)\n                .compile_well_known_types(false)\n                .generate_server(service, \"\");\n\n            self.servers.extend(server);\n        }\n\n        if self.builder.build_client {\n            let client = CodeGenBuilder::new()\n                .emit_package(true)\n                .compile_well_known_types(false)\n                .build_transport(self.builder.build_transport)\n                .generate_client(service, \"\");\n\n            self.clients.extend(client);\n        }\n    }\n\n    fn finalize(&mut self, buf: &mut String) {\n        if self.builder.build_client && !self.clients.is_empty() {\n            let clients = &self.clients;\n\n            let client_service = quote::quote! {\n                #clients\n            };\n\n            let ast: syn::File = syn::parse2(client_service).expect(\"not a valid tokenstream\");\n            let code = prettyplease::unparse(&ast);\n            buf.push_str(&code);\n\n            self.clients = TokenStream::default();\n        }\n\n        if self.builder.build_server && !self.servers.is_empty() {\n            let servers = &self.servers;\n\n            let server_service = quote::quote! {\n                #servers\n            };\n\n            let ast: syn::File = syn::parse2(server_service).expect(\"not a valid tokenstream\");\n            let code = prettyplease::unparse(&ast);\n            buf.push_str(&code);\n\n            self.servers = TokenStream::default();\n        }\n    }\n}\n\n/// Service generator builder.\n#[derive(Debug)]\npub struct Builder {\n    build_server: bool,\n    build_client: bool,\n    build_transport: bool,\n\n    out_dir: Option<PathBuf>,\n}\n\nimpl Default for Builder {\n    fn default() -> Self {\n        Self {\n            build_server: true,\n            build_client: true,\n            build_transport: true,\n            out_dir: None,\n        }\n    }\n}\n\nimpl Builder {\n    /// Create a new Builder\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Enable or disable gRPC client code generation.\n    ///\n    /// Defaults to enabling client code generation.\n    pub fn build_client(mut self, enable: bool) -> Self {\n        self.build_client = enable;\n        self\n    }\n\n    /// Enable or disable gRPC server code generation.\n    ///\n    /// Defaults to enabling server code generation.\n    pub fn build_server(mut self, enable: bool) -> Self {\n        self.build_server = enable;\n        self\n    }\n\n    /// Enable or disable generated clients and servers to have built-in tonic\n    /// transport features.\n    ///\n    /// When the `transport` feature is disabled this does nothing.\n    pub fn build_transport(mut self, enable: bool) -> Self {\n        self.build_transport = enable;\n        self\n    }\n\n    /// Set the output directory to generate code to.\n    ///\n    /// Defaults to the `OUT_DIR` environment variable.\n    pub fn out_dir(mut self, out_dir: impl AsRef<Path>) -> Self {\n        self.out_dir = Some(out_dir.as_ref().to_path_buf());\n        self\n    }\n\n    /// Performs code generation for the provided services.\n    ///\n    /// Generated services will be output into the directory specified by `out_dir`\n    /// with files named `<package_name>.<service_name>.rs`.\n    pub fn compile(self, services: &[Service]) {\n        let out_dir = if let Some(out_dir) = self.out_dir.as_ref() {\n            out_dir.clone()\n        } else {\n            PathBuf::from(std::env::var(\"OUT_DIR\").unwrap())\n        };\n\n        let mut generator = ServiceGenerator {\n            builder: self,\n            clients: TokenStream::default(),\n            servers: TokenStream::default(),\n        };\n\n        for service in services {\n            generator.generate(service);\n            let mut output = String::new();\n            generator.finalize(&mut output);\n\n            let out_file = out_dir.join(format!(\"{}.{}.rs\", service.package, service.name));\n            fs::write(out_file, output).unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-build/src/server.rs",
    "content": "use std::collections::HashSet;\n\nuse super::{Attributes, Method, Service};\nuse crate::{\n    format_method_name, format_method_path, format_service_name, generate_doc_comment,\n    generate_doc_comments, naive_snake_case,\n};\nuse proc_macro2::{Span, TokenStream};\nuse quote::quote;\nuse syn::{Ident, Lit, LitStr};\n\n#[allow(clippy::too_many_arguments)]\npub(crate) fn generate_internal<T: Service>(\n    service: &T,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    attributes: &Attributes,\n    disable_comments: &HashSet<String>,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n) -> TokenStream {\n    let methods = generate_methods(\n        service,\n        emit_package,\n        proto_path,\n        compile_well_known_types,\n        use_arc_self,\n        generate_default_stubs,\n    );\n\n    let server_service = quote::format_ident!(\"{}Server\", service.name());\n    let server_trait = quote::format_ident!(\"{}\", service.name());\n    let server_mod = quote::format_ident!(\"{}_server\", naive_snake_case(service.name()));\n    let trait_attributes = attributes.for_trait(service.name());\n    let generated_trait = generate_trait(\n        service,\n        emit_package,\n        proto_path,\n        compile_well_known_types,\n        server_trait.clone(),\n        disable_comments,\n        use_arc_self,\n        generate_default_stubs,\n        trait_attributes,\n    );\n    let package = if emit_package { service.package() } else { \"\" };\n    // Transport based implementations\n    let service_name = format_service_name(service, emit_package);\n\n    let service_doc = if disable_comments.contains(&service_name) {\n        TokenStream::new()\n    } else {\n        generate_doc_comments(service.comment())\n    };\n\n    let named = generate_named(&server_service, &service_name);\n    let mod_attributes = attributes.for_mod(package);\n    let struct_attributes = attributes.for_struct(&service_name);\n\n    let configure_compression_methods = quote! {\n        /// Enable decompressing requests with the given encoding.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.accept_compression_encodings.enable(encoding);\n            self\n        }\n\n        /// Compress responses with the given encoding, if the client supports it.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.send_compression_encodings.enable(encoding);\n            self\n        }\n    };\n\n    let configure_max_message_size_methods = quote! {\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.max_decoding_message_size = Some(limit);\n            self\n        }\n\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.max_encoding_message_size = Some(limit);\n            self\n        }\n    };\n\n    quote! {\n        /// Generated server implementations.\n        #(#mod_attributes)*\n        pub mod #server_mod {\n            #![allow(\n                unused_variables,\n                dead_code,\n                missing_docs,\n                clippy::wildcard_imports,\n                // will trigger if compression is disabled\n                clippy::let_unit_value,\n            )]\n            use tonic::codegen::*;\n\n            #generated_trait\n\n            #service_doc\n            #(#struct_attributes)*\n            #[derive(Debug)]\n            pub struct #server_service<T> {\n                inner: Arc<T>,\n                accept_compression_encodings: EnabledCompressionEncodings,\n                send_compression_encodings: EnabledCompressionEncodings,\n                max_decoding_message_size: Option<usize>,\n                max_encoding_message_size: Option<usize>,\n            }\n\n            impl<T> #server_service<T> {\n                pub fn new(inner: T) -> Self {\n                    Self::from_arc(Arc::new(inner))\n                }\n\n                pub fn from_arc(inner: Arc<T>) -> Self {\n                    Self {\n                        inner,\n                        accept_compression_encodings: Default::default(),\n                        send_compression_encodings: Default::default(),\n                        max_decoding_message_size: None,\n                        max_encoding_message_size: None,\n                    }\n                }\n\n                pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>\n                where\n                    F: tonic::service::Interceptor,\n                {\n                    InterceptedService::new(Self::new(inner), interceptor)\n                }\n\n                #configure_compression_methods\n\n                #configure_max_message_size_methods\n            }\n\n            impl<T, B> tonic::codegen::Service<http::Request<B>> for #server_service<T>\n                where\n                    T: #server_trait,\n                    B: Body + std::marker::Send + 'static,\n                    B::Error: Into<StdError> + std::marker::Send + 'static,\n            {\n                type Response = http::Response<tonic::body::Body>;\n                type Error = std::convert::Infallible;\n                type Future = BoxFuture<Self::Response, Self::Error>;\n\n                fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {\n                    Poll::Ready(Ok(()))\n                }\n\n                fn call(&mut self, req: http::Request<B>) -> Self::Future {\n                    match req.uri().path() {\n                        #methods\n\n                        _ => Box::pin(async move {\n                            let mut response = http::Response::new(tonic::body::Body::default());\n                            let headers = response.headers_mut();\n                            headers.insert(tonic::Status::GRPC_STATUS, (tonic::Code::Unimplemented as i32).into());\n                            headers.insert(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE);\n                            Ok(response)\n                        }),\n                    }\n                }\n            }\n\n            impl<T> Clone for #server_service<T> {\n                fn clone(&self) -> Self {\n                    let inner = self.inner.clone();\n                    Self {\n                        inner,\n                        accept_compression_encodings: self.accept_compression_encodings,\n                        send_compression_encodings: self.send_compression_encodings,\n                        max_decoding_message_size: self.max_decoding_message_size,\n                        max_encoding_message_size: self.max_encoding_message_size,\n                    }\n                }\n            }\n\n            #named\n        }\n    }\n}\n\n#[allow(clippy::too_many_arguments)]\nfn generate_trait<T: Service>(\n    service: &T,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    server_trait: Ident,\n    disable_comments: &HashSet<String>,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n    trait_attributes: Vec<syn::Attribute>,\n) -> TokenStream {\n    let methods = generate_trait_methods(\n        service,\n        emit_package,\n        proto_path,\n        compile_well_known_types,\n        disable_comments,\n        use_arc_self,\n        generate_default_stubs,\n    );\n    let trait_doc = generate_doc_comment(format!(\n        \" Generated trait containing gRPC methods that should be implemented for use with {}Server.\",\n        service.name()\n    ));\n\n    quote! {\n        #trait_doc\n        #(#trait_attributes)*\n        #[async_trait]\n        pub trait #server_trait : std::marker::Send + std::marker::Sync + 'static {\n            #methods\n        }\n    }\n}\n\nfn generate_trait_methods<T: Service>(\n    service: &T,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    disable_comments: &HashSet<String>,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n) -> TokenStream {\n    let mut stream = TokenStream::new();\n\n    for method in service.methods() {\n        let name = quote::format_ident!(\"{}\", method.name());\n\n        let (req_message, res_message) =\n            method.request_response_name(proto_path, compile_well_known_types);\n\n        let method_doc =\n            if disable_comments.contains(&format_method_name(service, method, emit_package)) {\n                TokenStream::new()\n            } else {\n                generate_doc_comments(method.comment())\n            };\n\n        let self_param = if use_arc_self {\n            quote!(self: std::sync::Arc<Self>)\n        } else {\n            quote!(&self)\n        };\n\n        let method = match (\n            method.client_streaming(),\n            method.server_streaming(),\n            generate_default_stubs,\n        ) {\n            (false, false, true) => {\n                quote! {\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<#req_message>)\n                        -> std::result::Result<tonic::Response<#res_message>, tonic::Status> {\n                        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n                    }\n                }\n            }\n            (false, false, false) => {\n                quote! {\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<#req_message>)\n                        -> std::result::Result<tonic::Response<#res_message>, tonic::Status>;\n                }\n            }\n            (true, false, true) => {\n                quote! {\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<tonic::Streaming<#req_message>>)\n                        -> std::result::Result<tonic::Response<#res_message>, tonic::Status> {\n                        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n                    }\n                }\n            }\n            (true, false, false) => {\n                quote! {\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<tonic::Streaming<#req_message>>)\n                        -> std::result::Result<tonic::Response<#res_message>, tonic::Status>;\n                }\n            }\n            (false, true, true) => {\n                quote! {\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<#req_message>)\n                        -> std::result::Result<tonic::Response<BoxStream<#res_message>>, tonic::Status> {\n                        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n                    }\n                }\n            }\n            (false, true, false) => {\n                let stream = quote::format_ident!(\"{}Stream\", method.identifier());\n                let stream_doc = generate_doc_comment(format!(\n                    \" Server streaming response type for the {} method.\",\n                    method.identifier()\n                ));\n\n                quote! {\n                    #stream_doc\n                    type #stream: tonic::codegen::tokio_stream::Stream<Item = std::result::Result<#res_message, tonic::Status>> + std::marker::Send + 'static;\n\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<#req_message>)\n                        -> std::result::Result<tonic::Response<Self::#stream>, tonic::Status>;\n                }\n            }\n            (true, true, true) => {\n                quote! {\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<tonic::Streaming<#req_message>>)\n                        -> std::result::Result<tonic::Response<BoxStream<#res_message>>, tonic::Status> {\n                        Err(tonic::Status::unimplemented(\"Not yet implemented\"))\n                    }\n                }\n            }\n            (true, true, false) => {\n                let stream = quote::format_ident!(\"{}Stream\", method.identifier());\n                let stream_doc = generate_doc_comment(format!(\n                    \" Server streaming response type for the {} method.\",\n                    method.identifier()\n                ));\n\n                quote! {\n                    #stream_doc\n                    type #stream: tonic::codegen::tokio_stream::Stream<Item = std::result::Result<#res_message, tonic::Status>> + std::marker::Send + 'static;\n\n                    #method_doc\n                    async fn #name(#self_param, request: tonic::Request<tonic::Streaming<#req_message>>)\n                        -> std::result::Result<tonic::Response<Self::#stream>, tonic::Status>;\n                }\n            }\n        };\n\n        stream.extend(method);\n    }\n\n    stream\n}\n\nfn generate_named(server_service: &syn::Ident, service_name: &str) -> TokenStream {\n    let service_name = syn::LitStr::new(service_name, proc_macro2::Span::call_site());\n    let name_doc = generate_doc_comment(\" Generated gRPC service name\");\n\n    quote! {\n        #name_doc\n        pub const SERVICE_NAME: &str = #service_name;\n\n        impl<T> tonic::server::NamedService for #server_service<T> {\n            const NAME: &'static str = SERVICE_NAME;\n        }\n    }\n}\n\nfn generate_methods<T: Service>(\n    service: &T,\n    emit_package: bool,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n) -> TokenStream {\n    let mut stream = TokenStream::new();\n\n    for method in service.methods() {\n        let path = format_method_path(service, method, emit_package);\n        let method_path = Lit::Str(LitStr::new(&path, Span::call_site()));\n        let ident = quote::format_ident!(\"{}\", method.name());\n        let server_trait = quote::format_ident!(\"{}\", service.name());\n\n        let method_stream = match (method.client_streaming(), method.server_streaming()) {\n            (false, false) => generate_unary(\n                method,\n                proto_path,\n                compile_well_known_types,\n                ident,\n                server_trait,\n                use_arc_self,\n            ),\n\n            (false, true) => generate_server_streaming(\n                method,\n                proto_path,\n                compile_well_known_types,\n                ident.clone(),\n                server_trait,\n                use_arc_self,\n                generate_default_stubs,\n            ),\n            (true, false) => generate_client_streaming(\n                method,\n                proto_path,\n                compile_well_known_types,\n                ident.clone(),\n                server_trait,\n                use_arc_self,\n            ),\n\n            (true, true) => generate_streaming(\n                method,\n                proto_path,\n                compile_well_known_types,\n                ident.clone(),\n                server_trait,\n                use_arc_self,\n                generate_default_stubs,\n            ),\n        };\n\n        let method = quote! {\n            #method_path => {\n                #method_stream\n            }\n        };\n        stream.extend(method);\n    }\n\n    stream\n}\n\nfn generate_unary<T: Method>(\n    method: &T,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    method_ident: Ident,\n    server_trait: Ident,\n    use_arc_self: bool,\n) -> TokenStream {\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n\n    let service_ident = quote::format_ident!(\"{}Svc\", method.identifier());\n\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n\n    let inner_arg = if use_arc_self {\n        quote!(inner)\n    } else {\n        quote!(&inner)\n    };\n\n    quote! {\n        #[allow(non_camel_case_types)]\n        struct #service_ident<T: #server_trait >(pub Arc<T>);\n\n        impl<T: #server_trait> tonic::server::UnaryService<#request> for #service_ident<T> {\n            type Response = #response;\n            type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;\n\n            fn call(&mut self, request: tonic::Request<#request>) -> Self::Future {\n                let inner = Arc::clone(&self.0);\n                let fut = async move {\n                    <T as #server_trait>::#method_ident(#inner_arg, request).await\n                };\n                Box::pin(fut)\n            }\n        }\n\n        let accept_compression_encodings = self.accept_compression_encodings;\n        let send_compression_encodings = self.send_compression_encodings;\n        let max_decoding_message_size = self.max_decoding_message_size;\n        let max_encoding_message_size = self.max_encoding_message_size;\n        let inner = self.inner.clone();\n        let fut = async move {\n            let method = #service_ident(inner);\n            let codec = #codec_name::default();\n\n            let mut grpc = tonic::server::Grpc::new(codec)\n                .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n                .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n            let res = grpc.unary(method, req).await;\n            Ok(res)\n        };\n\n        Box::pin(fut)\n    }\n}\n\nfn generate_server_streaming<T: Method>(\n    method: &T,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    method_ident: Ident,\n    server_trait: Ident,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n) -> TokenStream {\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n\n    let service_ident = quote::format_ident!(\"{}Svc\", method.identifier());\n\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n\n    let response_stream = if !generate_default_stubs {\n        let stream = quote::format_ident!(\"{}Stream\", method.identifier());\n        quote!(type ResponseStream = T::#stream)\n    } else {\n        quote!(type ResponseStream = BoxStream<#response>)\n    };\n\n    let inner_arg = if use_arc_self {\n        quote!(inner)\n    } else {\n        quote!(&inner)\n    };\n\n    quote! {\n        #[allow(non_camel_case_types)]\n        struct #service_ident<T: #server_trait >(pub Arc<T>);\n\n        impl<T: #server_trait> tonic::server::ServerStreamingService<#request> for #service_ident<T> {\n            type Response = #response;\n            #response_stream;\n            type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;\n\n            fn call(&mut self, request: tonic::Request<#request>) -> Self::Future {\n                let inner = Arc::clone(&self.0);\n                let fut = async move {\n                    <T as #server_trait>::#method_ident(#inner_arg, request).await\n                };\n                Box::pin(fut)\n            }\n        }\n\n        let accept_compression_encodings = self.accept_compression_encodings;\n        let send_compression_encodings = self.send_compression_encodings;\n        let max_decoding_message_size = self.max_decoding_message_size;\n        let max_encoding_message_size = self.max_encoding_message_size;\n        let inner = self.inner.clone();\n        let fut = async move {\n            let method = #service_ident(inner);\n            let codec = #codec_name::default();\n\n            let mut grpc = tonic::server::Grpc::new(codec)\n                .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n                .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n            let res = grpc.server_streaming(method, req).await;\n            Ok(res)\n        };\n\n        Box::pin(fut)\n    }\n}\n\nfn generate_client_streaming<T: Method>(\n    method: &T,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    method_ident: Ident,\n    server_trait: Ident,\n    use_arc_self: bool,\n) -> TokenStream {\n    let service_ident = quote::format_ident!(\"{}Svc\", method.identifier());\n\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n\n    let inner_arg = if use_arc_self {\n        quote!(inner)\n    } else {\n        quote!(&inner)\n    };\n\n    quote! {\n        #[allow(non_camel_case_types)]\n        struct #service_ident<T: #server_trait >(pub Arc<T>);\n\n        impl<T: #server_trait> tonic::server::ClientStreamingService<#request> for #service_ident<T>\n        {\n            type Response = #response;\n            type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;\n\n            fn call(&mut self, request: tonic::Request<tonic::Streaming<#request>>) -> Self::Future {\n                let inner = Arc::clone(&self.0);\n                let fut = async move {\n                    <T as #server_trait>::#method_ident(#inner_arg, request).await\n                };\n                Box::pin(fut)\n            }\n        }\n\n        let accept_compression_encodings = self.accept_compression_encodings;\n        let send_compression_encodings = self.send_compression_encodings;\n        let max_decoding_message_size = self.max_decoding_message_size;\n        let max_encoding_message_size = self.max_encoding_message_size;\n        let inner = self.inner.clone();\n        let fut = async move {\n            let method = #service_ident(inner);\n            let codec = #codec_name::default();\n\n            let mut grpc = tonic::server::Grpc::new(codec)\n                .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n                .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n            let res = grpc.client_streaming(method, req).await;\n            Ok(res)\n        };\n\n        Box::pin(fut)\n    }\n}\n\nfn generate_streaming<T: Method>(\n    method: &T,\n    proto_path: &str,\n    compile_well_known_types: bool,\n    method_ident: Ident,\n    server_trait: Ident,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n) -> TokenStream {\n    let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();\n\n    let service_ident = quote::format_ident!(\"{}Svc\", method.identifier());\n\n    let (request, response) = method.request_response_name(proto_path, compile_well_known_types);\n\n    let response_stream = if !generate_default_stubs {\n        let stream = quote::format_ident!(\"{}Stream\", method.identifier());\n        quote!(type ResponseStream = T::#stream)\n    } else {\n        quote!(type ResponseStream = BoxStream<#response>)\n    };\n\n    let inner_arg = if use_arc_self {\n        quote!(inner)\n    } else {\n        quote!(&inner)\n    };\n\n    quote! {\n        #[allow(non_camel_case_types)]\n        struct #service_ident<T: #server_trait>(pub Arc<T>);\n\n        impl<T: #server_trait> tonic::server::StreamingService<#request> for #service_ident<T>\n        {\n            type Response = #response;\n            #response_stream;\n            type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;\n\n            fn call(&mut self, request: tonic::Request<tonic::Streaming<#request>>) -> Self::Future {\n                let inner = Arc::clone(&self.0);\n                let fut = async move {\n                    <T as #server_trait>::#method_ident(#inner_arg, request).await\n                };\n                Box::pin(fut)\n            }\n        }\n\n        let accept_compression_encodings = self.accept_compression_encodings;\n        let send_compression_encodings = self.send_compression_encodings;\n        let max_decoding_message_size = self.max_decoding_message_size;\n        let max_encoding_message_size = self.max_encoding_message_size;\n        let inner = self.inner.clone();\n        let fut = async move {\n            let method = #service_ident(inner);\n            let codec = #codec_name::default();\n\n            let mut grpc = tonic::server::Grpc::new(codec)\n                .apply_compression_config(accept_compression_encodings, send_compression_encodings)\n                .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);\n\n            let res = grpc.streaming(method, req).await;\n            Ok(res)\n        };\n\n        Box::pin(fut)\n    }\n}\n"
  },
  {
    "path": "tonic-health/Cargo.toml",
    "content": "[package]\nauthors = [\"James Nugent <james@jen20.com>\"]\ncategories = [\"network-programming\", \"asynchronous\"]\ndescription = \"\"\"\nHealth Checking module of `tonic` gRPC implementation.\n\"\"\"\nedition = \"2024\"\nhomepage = \"https://github.com/hyperium/tonic\"\nkeywords = [\"rpc\", \"grpc\", \"async\", \"healthcheck\"]\nlicense = \"MIT\"\nname = \"tonic-health\"\nreadme = \"README.md\"\nrepository = \"https://github.com/hyperium/tonic\"\nversion = \"0.14.5\"\nrust-version = { workspace = true }\n\n[dependencies]\nprost = \"0.14\"\ntokio = {version = \"1.0\", features = [\"sync\"]}\ntokio-stream = {version = \"0.1\", default-features = false, features = [\"sync\"]}\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false, features = [\"codegen\"] }\ntonic-prost = { version = \"0.14.0\", path = \"../tonic-prost\", default-features = false }\n\n[dev-dependencies]\ntokio = {version = \"1.0\", features = [\"rt-multi-thread\", \"macros\"]}\nprost-types = \"0.14.0\"\n\n[lints]\nworkspace = true\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  \"tonic::*\",\n\n  # major released\n  \"bytes::*\",\n  \"http::*\",\n  \"http_body::*\",\n\n  # not major released\n  \"prost::*\",\n\n  \"futures_core::stream::Stream\",\n  \"tower_service::Service\",\n]\n"
  },
  {
    "path": "tonic-health/README.md",
    "content": "# tonic-health\n\nA `tonic` based gRPC healthcheck implementation. It closely follows the official [health checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md), although it may not implement all features described in the specs.\n\nPlease follow the example in the [main repo](https://github.com/hyperium/tonic/tree/master/examples/src/health) to see how it works.\n\n## Features\n\n- transport: Provides the ability to set the service by using the type system and the\n`NamedService` trait. You can use it like that:\n```rust\n    let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;\n    let client = HealthClient::new(conn);\n```\n"
  },
  {
    "path": "tonic-health/proto/health.proto",
    "content": "// Copyright 2015 The gRPC Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// The canonical version of this proto can be found at\n// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto\n\nsyntax = \"proto3\";\n\npackage grpc.health.v1;\n\noption csharp_namespace = \"Grpc.Health.V1\";\noption go_package = \"google.golang.org/grpc/health/grpc_health_v1\";\noption java_multiple_files = true;\noption java_outer_classname = \"HealthProto\";\noption java_package = \"io.grpc.health.v1\";\n\nmessage HealthCheckRequest {\n  string service = 1;\n}\n\nmessage HealthCheckResponse {\n  enum ServingStatus {\n    UNKNOWN = 0;\n    SERVING = 1;\n    NOT_SERVING = 2;\n    SERVICE_UNKNOWN = 3;  // Used only by the Watch method.\n  }\n  ServingStatus status = 1;\n}\n\nservice Health {\n  // If the requested service is unknown, the call will fail with status\n  // NOT_FOUND.\n  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);\n\n  // Performs a watch for the serving status of the requested service.\n  // The server will immediately send back a message indicating the current\n  // serving status.  It will then subsequently send a new message whenever\n  // the service's serving status changes.\n  //\n  // If the requested service is unknown when the call is received, the\n  // server will send a message setting the serving status to\n  // SERVICE_UNKNOWN but will *not* terminate the call.  If at some\n  // future point, the serving status of the service becomes known, the\n  // server will send a new message with the service's serving status.\n  //\n  // If the call terminates with status UNIMPLEMENTED, then clients\n  // should assume this method is not supported and should not retry the\n  // call.  If the call terminates with any other status (including OK),\n  // clients should retry the call with appropriate exponential backoff.\n  rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);\n}\n"
  },
  {
    "path": "tonic-health/src/generated/grpc_health_v1.rs",
    "content": "// This file is @generated by prost-build.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct HealthCheckRequest {\n    #[prost(string, tag = \"1\")]\n    pub service: ::prost::alloc::string::String,\n}\n#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]\npub struct HealthCheckResponse {\n    #[prost(enumeration = \"health_check_response::ServingStatus\", tag = \"1\")]\n    pub status: i32,\n}\n/// Nested message and enum types in `HealthCheckResponse`.\npub mod health_check_response {\n    #[derive(\n        Clone,\n        Copy,\n        Debug,\n        PartialEq,\n        Eq,\n        Hash,\n        PartialOrd,\n        Ord,\n        ::prost::Enumeration\n    )]\n    #[repr(i32)]\n    pub enum ServingStatus {\n        Unknown = 0,\n        Serving = 1,\n        NotServing = 2,\n        /// Used only by the Watch method.\n        ServiceUnknown = 3,\n    }\n    impl ServingStatus {\n        /// String value of the enum field names used in the ProtoBuf definition.\n        ///\n        /// The values are not transformed in any way and thus are considered stable\n        /// (if the ProtoBuf definition does not change) and safe for programmatic use.\n        pub fn as_str_name(&self) -> &'static str {\n            match self {\n                Self::Unknown => \"UNKNOWN\",\n                Self::Serving => \"SERVING\",\n                Self::NotServing => \"NOT_SERVING\",\n                Self::ServiceUnknown => \"SERVICE_UNKNOWN\",\n            }\n        }\n        /// Creates an enum from field names used in the ProtoBuf definition.\n        pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {\n            match value {\n                \"UNKNOWN\" => Some(Self::Unknown),\n                \"SERVING\" => Some(Self::Serving),\n                \"NOT_SERVING\" => Some(Self::NotServing),\n                \"SERVICE_UNKNOWN\" => Some(Self::ServiceUnknown),\n                _ => None,\n            }\n        }\n    }\n}\n/// Generated client implementations.\npub mod health_client {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    use tonic::codegen::http::Uri;\n    #[derive(Debug, Clone)]\n    pub struct HealthClient<T> {\n        inner: tonic::client::Grpc<T>,\n    }\n    impl<T> HealthClient<T>\n    where\n        T: tonic::client::GrpcService<tonic::body::Body>,\n        T::Error: Into<StdError>,\n        T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,\n        <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,\n    {\n        pub fn new(inner: T) -> Self {\n            let inner = tonic::client::Grpc::new(inner);\n            Self { inner }\n        }\n        pub fn with_origin(inner: T, origin: Uri) -> Self {\n            let inner = tonic::client::Grpc::with_origin(inner, origin);\n            Self { inner }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> HealthClient<InterceptedService<T, F>>\n        where\n            F: tonic::service::Interceptor,\n            T::ResponseBody: Default,\n            T: tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n                Response = http::Response<\n                    <T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody,\n                >,\n            >,\n            <T as tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n            >>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,\n        {\n            HealthClient::new(InterceptedService::new(inner, interceptor))\n        }\n        /// Compress requests with the given encoding.\n        ///\n        /// This requires the server to support it otherwise it might respond with an\n        /// error.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.send_compressed(encoding);\n            self\n        }\n        /// Enable decompressing responses.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.accept_compressed(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_decoding_message_size(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_encoding_message_size(limit);\n            self\n        }\n        /// If the requested service is unknown, the call will fail with status\n        /// NOT_FOUND.\n        pub async fn check(\n            &mut self,\n            request: impl tonic::IntoRequest<super::HealthCheckRequest>,\n        ) -> std::result::Result<\n            tonic::Response<super::HealthCheckResponse>,\n            tonic::Status,\n        > {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.health.v1.Health/Check\",\n            );\n            let mut req = request.into_request();\n            req.extensions_mut()\n                .insert(GrpcMethod::new(\"grpc.health.v1.Health\", \"Check\"));\n            self.inner.unary(req, path, codec).await\n        }\n        /// Performs a watch for the serving status of the requested service.\n        /// The server will immediately send back a message indicating the current\n        /// serving status.  It will then subsequently send a new message whenever\n        /// the service's serving status changes.\n        ///\n        /// If the requested service is unknown when the call is received, the\n        /// server will send a message setting the serving status to\n        /// SERVICE_UNKNOWN but will *not* terminate the call.  If at some\n        /// future point, the serving status of the service becomes known, the\n        /// server will send a new message with the service's serving status.\n        ///\n        /// If the call terminates with status UNIMPLEMENTED, then clients\n        /// should assume this method is not supported and should not retry the\n        /// call.  If the call terminates with any other status (including OK),\n        /// clients should retry the call with appropriate exponential backoff.\n        pub async fn watch(\n            &mut self,\n            request: impl tonic::IntoRequest<super::HealthCheckRequest>,\n        ) -> std::result::Result<\n            tonic::Response<tonic::codec::Streaming<super::HealthCheckResponse>>,\n            tonic::Status,\n        > {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.health.v1.Health/Watch\",\n            );\n            let mut req = request.into_request();\n            req.extensions_mut()\n                .insert(GrpcMethod::new(\"grpc.health.v1.Health\", \"Watch\"));\n            self.inner.server_streaming(req, path, codec).await\n        }\n    }\n}\n/// Generated server implementations.\npub mod health_server {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    /// Generated trait containing gRPC methods that should be implemented for use with HealthServer.\n    #[async_trait]\n    pub trait Health: std::marker::Send + std::marker::Sync + 'static {\n        /// If the requested service is unknown, the call will fail with status\n        /// NOT_FOUND.\n        async fn check(\n            &self,\n            request: tonic::Request<super::HealthCheckRequest>,\n        ) -> std::result::Result<\n            tonic::Response<super::HealthCheckResponse>,\n            tonic::Status,\n        >;\n        /// Server streaming response type for the Watch method.\n        type WatchStream: tonic::codegen::tokio_stream::Stream<\n                Item = std::result::Result<super::HealthCheckResponse, tonic::Status>,\n            >\n            + std::marker::Send\n            + 'static;\n        /// Performs a watch for the serving status of the requested service.\n        /// The server will immediately send back a message indicating the current\n        /// serving status.  It will then subsequently send a new message whenever\n        /// the service's serving status changes.\n        ///\n        /// If the requested service is unknown when the call is received, the\n        /// server will send a message setting the serving status to\n        /// SERVICE_UNKNOWN but will *not* terminate the call.  If at some\n        /// future point, the serving status of the service becomes known, the\n        /// server will send a new message with the service's serving status.\n        ///\n        /// If the call terminates with status UNIMPLEMENTED, then clients\n        /// should assume this method is not supported and should not retry the\n        /// call.  If the call terminates with any other status (including OK),\n        /// clients should retry the call with appropriate exponential backoff.\n        async fn watch(\n            &self,\n            request: tonic::Request<super::HealthCheckRequest>,\n        ) -> std::result::Result<tonic::Response<Self::WatchStream>, tonic::Status>;\n    }\n    #[derive(Debug)]\n    pub struct HealthServer<T> {\n        inner: Arc<T>,\n        accept_compression_encodings: EnabledCompressionEncodings,\n        send_compression_encodings: EnabledCompressionEncodings,\n        max_decoding_message_size: Option<usize>,\n        max_encoding_message_size: Option<usize>,\n    }\n    impl<T> HealthServer<T> {\n        pub fn new(inner: T) -> Self {\n            Self::from_arc(Arc::new(inner))\n        }\n        pub fn from_arc(inner: Arc<T>) -> Self {\n            Self {\n                inner,\n                accept_compression_encodings: Default::default(),\n                send_compression_encodings: Default::default(),\n                max_decoding_message_size: None,\n                max_encoding_message_size: None,\n            }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> InterceptedService<Self, F>\n        where\n            F: tonic::service::Interceptor,\n        {\n            InterceptedService::new(Self::new(inner), interceptor)\n        }\n        /// Enable decompressing requests with the given encoding.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.accept_compression_encodings.enable(encoding);\n            self\n        }\n        /// Compress responses with the given encoding, if the client supports it.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.send_compression_encodings.enable(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.max_decoding_message_size = Some(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.max_encoding_message_size = Some(limit);\n            self\n        }\n    }\n    impl<T, B> tonic::codegen::Service<http::Request<B>> for HealthServer<T>\n    where\n        T: Health,\n        B: Body + std::marker::Send + 'static,\n        B::Error: Into<StdError> + std::marker::Send + 'static,\n    {\n        type Response = http::Response<tonic::body::Body>;\n        type Error = std::convert::Infallible;\n        type Future = BoxFuture<Self::Response, Self::Error>;\n        fn poll_ready(\n            &mut self,\n            _cx: &mut Context<'_>,\n        ) -> Poll<std::result::Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n        fn call(&mut self, req: http::Request<B>) -> Self::Future {\n            match req.uri().path() {\n                \"/grpc.health.v1.Health/Check\" => {\n                    #[allow(non_camel_case_types)]\n                    struct CheckSvc<T: Health>(pub Arc<T>);\n                    impl<\n                        T: Health,\n                    > tonic::server::UnaryService<super::HealthCheckRequest>\n                    for CheckSvc<T> {\n                        type Response = super::HealthCheckResponse;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::Response>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<super::HealthCheckRequest>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as Health>::check(&inner, request).await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = CheckSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.unary(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                \"/grpc.health.v1.Health/Watch\" => {\n                    #[allow(non_camel_case_types)]\n                    struct WatchSvc<T: Health>(pub Arc<T>);\n                    impl<\n                        T: Health,\n                    > tonic::server::ServerStreamingService<super::HealthCheckRequest>\n                    for WatchSvc<T> {\n                        type Response = super::HealthCheckResponse;\n                        type ResponseStream = T::WatchStream;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::ResponseStream>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<super::HealthCheckRequest>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as Health>::watch(&inner, request).await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = WatchSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.server_streaming(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                _ => {\n                    Box::pin(async move {\n                        let mut response = http::Response::new(\n                            tonic::body::Body::default(),\n                        );\n                        let headers = response.headers_mut();\n                        headers\n                            .insert(\n                                tonic::Status::GRPC_STATUS,\n                                (tonic::Code::Unimplemented as i32).into(),\n                            );\n                        headers\n                            .insert(\n                                http::header::CONTENT_TYPE,\n                                tonic::metadata::GRPC_CONTENT_TYPE,\n                            );\n                        Ok(response)\n                    })\n                }\n            }\n        }\n    }\n    impl<T> Clone for HealthServer<T> {\n        fn clone(&self) -> Self {\n            let inner = self.inner.clone();\n            Self {\n                inner,\n                accept_compression_encodings: self.accept_compression_encodings,\n                send_compression_encodings: self.send_compression_encodings,\n                max_decoding_message_size: self.max_decoding_message_size,\n                max_encoding_message_size: self.max_encoding_message_size,\n            }\n        }\n    }\n    /// Generated gRPC service name\n    pub const SERVICE_NAME: &str = \"grpc.health.v1.Health\";\n    impl<T> tonic::server::NamedService for HealthServer<T> {\n        const NAME: &'static str = SERVICE_NAME;\n    }\n}\n"
  },
  {
    "path": "tonic-health/src/generated/grpc_health_v1_fds.rs",
    "content": "// This file is @generated by codegen.\n//  Copyright 2015 The gRPC Authors\n// \n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n// \n//      http://www.apache.org/licenses/LICENSE-2.0\n// \n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//  The canonical version of this proto can be found at\n//  https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto\n// \n/// Byte encoded FILE_DESCRIPTOR_SET.\npub const FILE_DESCRIPTOR_SET: &[u8] = &[\n    10u8, 158u8, 4u8, 10u8, 12u8, 104u8, 101u8, 97u8, 108u8, 116u8, 104u8, 46u8, 112u8,\n    114u8, 111u8, 116u8, 111u8, 18u8, 14u8, 103u8, 114u8, 112u8, 99u8, 46u8, 104u8,\n    101u8, 97u8, 108u8, 116u8, 104u8, 46u8, 118u8, 49u8, 34u8, 46u8, 10u8, 18u8, 72u8,\n    101u8, 97u8, 108u8, 116u8, 104u8, 67u8, 104u8, 101u8, 99u8, 107u8, 82u8, 101u8,\n    113u8, 117u8, 101u8, 115u8, 116u8, 18u8, 24u8, 10u8, 7u8, 115u8, 101u8, 114u8, 118u8,\n    105u8, 99u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 7u8, 115u8, 101u8, 114u8,\n    118u8, 105u8, 99u8, 101u8, 34u8, 177u8, 1u8, 10u8, 19u8, 72u8, 101u8, 97u8, 108u8,\n    116u8, 104u8, 67u8, 104u8, 101u8, 99u8, 107u8, 82u8, 101u8, 115u8, 112u8, 111u8,\n    110u8, 115u8, 101u8, 18u8, 73u8, 10u8, 6u8, 115u8, 116u8, 97u8, 116u8, 117u8, 115u8,\n    24u8, 1u8, 32u8, 1u8, 40u8, 14u8, 50u8, 49u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8,\n    104u8, 101u8, 97u8, 108u8, 116u8, 104u8, 46u8, 118u8, 49u8, 46u8, 72u8, 101u8, 97u8,\n    108u8, 116u8, 104u8, 67u8, 104u8, 101u8, 99u8, 107u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 46u8, 83u8, 101u8, 114u8, 118u8, 105u8, 110u8, 103u8,\n    83u8, 116u8, 97u8, 116u8, 117u8, 115u8, 82u8, 6u8, 115u8, 116u8, 97u8, 116u8, 117u8,\n    115u8, 34u8, 79u8, 10u8, 13u8, 83u8, 101u8, 114u8, 118u8, 105u8, 110u8, 103u8, 83u8,\n    116u8, 97u8, 116u8, 117u8, 115u8, 18u8, 11u8, 10u8, 7u8, 85u8, 78u8, 75u8, 78u8,\n    79u8, 87u8, 78u8, 16u8, 0u8, 18u8, 11u8, 10u8, 7u8, 83u8, 69u8, 82u8, 86u8, 73u8,\n    78u8, 71u8, 16u8, 1u8, 18u8, 15u8, 10u8, 11u8, 78u8, 79u8, 84u8, 95u8, 83u8, 69u8,\n    82u8, 86u8, 73u8, 78u8, 71u8, 16u8, 2u8, 18u8, 19u8, 10u8, 15u8, 83u8, 69u8, 82u8,\n    86u8, 73u8, 67u8, 69u8, 95u8, 85u8, 78u8, 75u8, 78u8, 79u8, 87u8, 78u8, 16u8, 3u8,\n    50u8, 174u8, 1u8, 10u8, 6u8, 72u8, 101u8, 97u8, 108u8, 116u8, 104u8, 18u8, 80u8,\n    10u8, 5u8, 67u8, 104u8, 101u8, 99u8, 107u8, 18u8, 34u8, 46u8, 103u8, 114u8, 112u8,\n    99u8, 46u8, 104u8, 101u8, 97u8, 108u8, 116u8, 104u8, 46u8, 118u8, 49u8, 46u8, 72u8,\n    101u8, 97u8, 108u8, 116u8, 104u8, 67u8, 104u8, 101u8, 99u8, 107u8, 82u8, 101u8,\n    113u8, 117u8, 101u8, 115u8, 116u8, 26u8, 35u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8,\n    104u8, 101u8, 97u8, 108u8, 116u8, 104u8, 46u8, 118u8, 49u8, 46u8, 72u8, 101u8, 97u8,\n    108u8, 116u8, 104u8, 67u8, 104u8, 101u8, 99u8, 107u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 18u8, 82u8, 10u8, 5u8, 87u8, 97u8, 116u8, 99u8, 104u8,\n    18u8, 34u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 104u8, 101u8, 97u8, 108u8, 116u8,\n    104u8, 46u8, 118u8, 49u8, 46u8, 72u8, 101u8, 97u8, 108u8, 116u8, 104u8, 67u8, 104u8,\n    101u8, 99u8, 107u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 26u8, 35u8, 46u8,\n    103u8, 114u8, 112u8, 99u8, 46u8, 104u8, 101u8, 97u8, 108u8, 116u8, 104u8, 46u8,\n    118u8, 49u8, 46u8, 72u8, 101u8, 97u8, 108u8, 116u8, 104u8, 67u8, 104u8, 101u8, 99u8,\n    107u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 48u8, 1u8, 66u8, 97u8,\n    10u8, 17u8, 105u8, 111u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 104u8, 101u8, 97u8,\n    108u8, 116u8, 104u8, 46u8, 118u8, 49u8, 66u8, 11u8, 72u8, 101u8, 97u8, 108u8, 116u8,\n    104u8, 80u8, 114u8, 111u8, 116u8, 111u8, 80u8, 1u8, 90u8, 44u8, 103u8, 111u8, 111u8,\n    103u8, 108u8, 101u8, 46u8, 103u8, 111u8, 108u8, 97u8, 110u8, 103u8, 46u8, 111u8,\n    114u8, 103u8, 47u8, 103u8, 114u8, 112u8, 99u8, 47u8, 104u8, 101u8, 97u8, 108u8,\n    116u8, 104u8, 47u8, 103u8, 114u8, 112u8, 99u8, 95u8, 104u8, 101u8, 97u8, 108u8,\n    116u8, 104u8, 95u8, 118u8, 49u8, 170u8, 2u8, 14u8, 71u8, 114u8, 112u8, 99u8, 46u8,\n    72u8, 101u8, 97u8, 108u8, 116u8, 104u8, 46u8, 86u8, 49u8, 98u8, 6u8, 112u8, 114u8,\n    111u8, 116u8, 111u8, 51u8,\n];\n"
  },
  {
    "path": "tonic-health/src/lib.rs",
    "content": "//! A `tonic` based gRPC healthcheck implementation.\n//!\n//! # Example\n//!\n//! An example can be found [here].\n//!\n//! [here]: https://github.com/hyperium/tonic/blob/master/examples/src/health/server.rs\n\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg\"\n)]\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nuse std::fmt::{Display, Formatter};\n\nmod generated {\n    #![allow(unreachable_pub)]\n    #![allow(missing_docs)]\n    #[rustfmt::skip]\n    pub mod grpc_health_v1;\n    #[rustfmt::skip]\n    pub mod grpc_health_v1_fds;\n\n    pub use grpc_health_v1_fds::FILE_DESCRIPTOR_SET;\n\n    #[cfg(test)]\n    mod tests {\n        use super::FILE_DESCRIPTOR_SET;\n        use prost::Message as _;\n\n        #[test]\n        fn file_descriptor_set_is_valid() {\n            prost_types::FileDescriptorSet::decode(FILE_DESCRIPTOR_SET).unwrap();\n        }\n    }\n}\n\n/// Generated protobuf types from the `grpc.health.v1` package.\npub mod pb {\n    pub use crate::generated::{FILE_DESCRIPTOR_SET, grpc_health_v1::*};\n}\n\npub mod server;\n\n/// An enumeration of values representing gRPC service health.\n#[derive(Copy, Clone, Debug, PartialEq, Eq)]\npub enum ServingStatus {\n    /// Unknown status\n    Unknown,\n    /// The service is currently up and serving requests.\n    Serving,\n    /// The service is currently down and not serving requests.\n    NotServing,\n}\n\nimpl Display for ServingStatus {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            ServingStatus::Unknown => f.write_str(\"Unknown\"),\n            ServingStatus::Serving => f.write_str(\"Serving\"),\n            ServingStatus::NotServing => f.write_str(\"NotServing\"),\n        }\n    }\n}\n\nimpl From<ServingStatus> for pb::health_check_response::ServingStatus {\n    fn from(s: ServingStatus) -> Self {\n        match s {\n            ServingStatus::Unknown => pb::health_check_response::ServingStatus::Unknown,\n            ServingStatus::Serving => pb::health_check_response::ServingStatus::Serving,\n            ServingStatus::NotServing => pb::health_check_response::ServingStatus::NotServing,\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-health/src/server.rs",
    "content": "//! Contains all healthcheck based server utilities.\n\nuse crate::ServingStatus;\nuse crate::pb::health_server::{Health, HealthServer};\nuse crate::pb::{HealthCheckRequest, HealthCheckResponse};\nuse std::collections::HashMap;\nuse std::fmt;\nuse std::sync::Arc;\nuse tokio::sync::{RwLock, watch};\nuse tokio_stream::Stream;\nuse tonic::{Request, Response, Status, server::NamedService};\n\n/// Creates a `HealthReporter` and a linked `HealthServer` pair. Together,\n/// these types can be used to serve the gRPC Health Checking service.\n///\n/// A `HealthReporter` is used to update the state of gRPC services.\n///\n/// A `HealthServer` is a Tonic gRPC server for the `grpc.health.v1.Health`,\n/// which can be added to a Tonic runtime using `add_service` on the runtime\n/// builder.\npub fn health_reporter() -> (HealthReporter, HealthServer<impl Health>) {\n    let reporter = HealthReporter::new();\n    let service = HealthService::new(reporter.statuses.clone());\n    let server = HealthServer::new(service);\n\n    (reporter, server)\n}\n\ntype StatusPair = (watch::Sender<ServingStatus>, watch::Receiver<ServingStatus>);\n\n/// A handle providing methods to update the health status of gRPC services. A\n/// `HealthReporter` is connected to a `HealthServer` which serves the statuses\n/// over the `grpc.health.v1.Health` service.\n#[derive(Clone, Debug)]\npub struct HealthReporter {\n    statuses: Arc<RwLock<HashMap<String, StatusPair>>>,\n}\n\nimpl HealthReporter {\n    /// Create a new HealthReporter with an initial service (named \"\"), corresponding to overall server health\n    pub fn new() -> Self {\n        // According to the gRPC Health Check specification, the empty service \"\" corresponds to the overall server health\n        let server_status = (\"\".to_string(), watch::channel(ServingStatus::Serving));\n\n        let statuses = Arc::new(RwLock::new(HashMap::from([server_status])));\n\n        HealthReporter { statuses }\n    }\n\n    /// Sets the status of the service implemented by `S` to `Serving`. This notifies any watchers\n    /// if there is a change in status.\n    pub async fn set_serving<S>(&self)\n    where\n        S: NamedService,\n    {\n        let service_name = <S as NamedService>::NAME;\n        self.set_service_status(service_name, ServingStatus::Serving)\n            .await;\n    }\n\n    /// Sets the status of the service implemented by `S` to `NotServing`. This notifies any watchers\n    /// if there is a change in status.\n    pub async fn set_not_serving<S>(&self)\n    where\n        S: NamedService,\n    {\n        let service_name = <S as NamedService>::NAME;\n        self.set_service_status(service_name, ServingStatus::NotServing)\n            .await;\n    }\n\n    /// Sets the status of the service with `service_name` to `status`. This notifies any watchers\n    /// if there is a change in status.\n    pub async fn set_service_status<S>(&self, service_name: S, status: ServingStatus)\n    where\n        S: AsRef<str>,\n    {\n        let service_name = service_name.as_ref();\n        let mut writer = self.statuses.write().await;\n        match writer.get(service_name) {\n            Some((tx, _)) => {\n                // We only ever hand out clones of the receiver, so the originally-created\n                // receiver should always be present, only being dropped when clearing the\n                // service status. Consequently, `tx.send` should not fail, making use\n                // of `expect` here safe.\n                tx.send(status).expect(\"channel should not be closed\");\n            }\n            None => {\n                writer.insert(service_name.to_string(), watch::channel(status));\n            }\n        };\n    }\n\n    /// Clear the status of the given service.\n    pub async fn clear_service_status(&mut self, service_name: &str) {\n        let mut writer = self.statuses.write().await;\n        let _ = writer.remove(service_name);\n    }\n}\n\nimpl Default for HealthReporter {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// A service providing implementations of gRPC health checking protocol.\n#[derive(Debug)]\npub struct HealthService {\n    statuses: Arc<RwLock<HashMap<String, StatusPair>>>,\n}\n\nimpl HealthService {\n    fn new(services: Arc<RwLock<HashMap<String, StatusPair>>>) -> Self {\n        HealthService { statuses: services }\n    }\n\n    /// Create a HealthService, carrying across the statuses from an existing HealthReporter\n    pub fn from_health_reporter(health_reporter: HealthReporter) -> Self {\n        Self::new(health_reporter.statuses)\n    }\n\n    async fn service_health(&self, service_name: &str) -> Option<ServingStatus> {\n        let reader = self.statuses.read().await;\n        reader.get(service_name).map(|p| *p.1.borrow())\n    }\n}\n\n#[tonic::async_trait]\nimpl Health for HealthService {\n    async fn check(\n        &self,\n        request: Request<HealthCheckRequest>,\n    ) -> Result<Response<HealthCheckResponse>, Status> {\n        let service_name = request.get_ref().service.as_str();\n        let Some(status) = self.service_health(service_name).await else {\n            return Err(Status::not_found(\"service not registered\"));\n        };\n\n        Ok(Response::new(HealthCheckResponse::new(status)))\n    }\n\n    type WatchStream = WatchStream;\n\n    async fn watch(\n        &self,\n        request: Request<HealthCheckRequest>,\n    ) -> Result<Response<Self::WatchStream>, Status> {\n        let service_name = request.get_ref().service.as_str();\n        let status_rx = match self.statuses.read().await.get(service_name) {\n            Some((_tx, rx)) => rx.clone(),\n            None => return Err(Status::not_found(\"service not registered\")),\n        };\n\n        Ok(Response::new(WatchStream::new(status_rx)))\n    }\n}\n\n/// A watch stream for the health service.\npub struct WatchStream {\n    inner: tokio_stream::wrappers::WatchStream<ServingStatus>,\n}\n\nimpl WatchStream {\n    fn new(status_rx: watch::Receiver<ServingStatus>) -> Self {\n        let inner = tokio_stream::wrappers::WatchStream::new(status_rx);\n        Self { inner }\n    }\n}\n\nimpl Stream for WatchStream {\n    type Item = Result<HealthCheckResponse, Status>;\n\n    fn poll_next(\n        mut self: std::pin::Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Option<Self::Item>> {\n        std::pin::Pin::new(&mut self.inner)\n            .poll_next(cx)\n            .map(|opt| opt.map(|status| Ok(HealthCheckResponse::new(status))))\n    }\n}\n\nimpl fmt::Debug for WatchStream {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"WatchStream\").finish()\n    }\n}\n\nimpl HealthCheckResponse {\n    fn new(status: ServingStatus) -> Self {\n        let status = crate::pb::health_check_response::ServingStatus::from(status) as i32;\n        Self { status }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::ServingStatus;\n    use crate::pb::HealthCheckRequest;\n    use crate::pb::health_server::Health;\n    use crate::server::{HealthReporter, HealthService};\n    use tokio::sync::watch;\n    use tokio_stream::StreamExt;\n    use tonic::{Code, Request, Status};\n\n    fn assert_serving_status(wire: i32, expected: ServingStatus) {\n        let expected = crate::pb::health_check_response::ServingStatus::from(expected) as i32;\n        assert_eq!(wire, expected);\n    }\n\n    fn assert_grpc_status(wire: Option<Status>, expected: Code) {\n        let wire = wire.expect(\"status is not None\").code();\n        assert_eq!(wire, expected);\n    }\n\n    async fn make_test_service() -> (HealthReporter, HealthService) {\n        let health_reporter = HealthReporter::new();\n\n        // insert test value\n        {\n            let mut statuses = health_reporter.statuses.write().await;\n            statuses.insert(\n                \"TestService\".to_string(),\n                watch::channel(ServingStatus::Unknown),\n            );\n        }\n\n        let health_service = HealthService::new(health_reporter.statuses.clone());\n        (health_reporter, health_service)\n    }\n\n    #[tokio::test]\n    async fn test_service_check() {\n        let (reporter, service) = make_test_service().await;\n\n        // Overall server health\n        let resp = service\n            .check(Request::new(HealthCheckRequest {\n                service: \"\".to_string(),\n            }))\n            .await;\n        assert!(resp.is_ok());\n        let resp = resp.unwrap().into_inner();\n        assert_serving_status(resp.status, ServingStatus::Serving);\n\n        // Unregistered service\n        let resp = service\n            .check(Request::new(HealthCheckRequest {\n                service: \"Unregistered\".to_string(),\n            }))\n            .await;\n        assert!(resp.is_err());\n        assert_grpc_status(resp.err(), Code::NotFound);\n\n        // Registered service - initial state\n        let resp = service\n            .check(Request::new(HealthCheckRequest {\n                service: \"TestService\".to_string(),\n            }))\n            .await;\n        assert!(resp.is_ok());\n        let resp = resp.unwrap().into_inner();\n        assert_serving_status(resp.status, ServingStatus::Unknown);\n\n        // Registered service - updated state\n        reporter\n            .set_service_status(\"TestService\", ServingStatus::Serving)\n            .await;\n        let resp = service\n            .check(Request::new(HealthCheckRequest {\n                service: \"TestService\".to_string(),\n            }))\n            .await;\n        assert!(resp.is_ok());\n        let resp = resp.unwrap().into_inner();\n        assert_serving_status(resp.status, ServingStatus::Serving);\n    }\n\n    #[tokio::test]\n    async fn test_service_watch() {\n        let (mut reporter, service) = make_test_service().await;\n\n        // Overall server health\n        let resp = service\n            .watch(Request::new(HealthCheckRequest {\n                service: \"\".to_string(),\n            }))\n            .await;\n        assert!(resp.is_ok());\n        let mut resp = resp.unwrap().into_inner();\n        let item = resp\n            .next()\n            .await\n            .expect(\"streamed response is Some\")\n            .expect(\"response is ok\");\n        assert_serving_status(item.status, ServingStatus::Serving);\n\n        // Unregistered service\n        let resp = service\n            .watch(Request::new(HealthCheckRequest {\n                service: \"Unregistered\".to_string(),\n            }))\n            .await;\n        assert!(resp.is_err());\n        assert_grpc_status(resp.err(), Code::NotFound);\n\n        // Registered service\n        let resp = service\n            .watch(Request::new(HealthCheckRequest {\n                service: \"TestService\".to_string(),\n            }))\n            .await;\n        assert!(resp.is_ok());\n        let mut resp = resp.unwrap().into_inner();\n\n        // Registered service - initial state\n        let item = resp\n            .next()\n            .await\n            .expect(\"streamed response is Some\")\n            .expect(\"response is ok\");\n        assert_serving_status(item.status, ServingStatus::Unknown);\n\n        // Registered service - updated state\n        reporter\n            .set_service_status(\"TestService\", ServingStatus::NotServing)\n            .await;\n\n        let item = resp\n            .next()\n            .await\n            .expect(\"streamed response is Some\")\n            .expect(\"response is ok\");\n        assert_serving_status(item.status, ServingStatus::NotServing);\n\n        // Registered service - updated state\n        reporter\n            .set_service_status(\"TestService\", ServingStatus::Serving)\n            .await;\n        let item = resp\n            .next()\n            .await\n            .expect(\"streamed response is Some\")\n            .expect(\"response is ok\");\n        assert_serving_status(item.status, ServingStatus::Serving);\n\n        // De-registered service\n        reporter.clear_service_status(\"TestService\").await;\n        let item = resp.next().await;\n        assert!(item.is_none());\n    }\n}\n"
  },
  {
    "path": "tonic-prost/Cargo.toml",
    "content": "[package]\nname = \"tonic-prost\"\nversion = \"0.14.5\"\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2024\"\nlicense = \"MIT\"\nrepository = \"https://github.com/hyperium/tonic\"\nhomepage = \"https://github.com/hyperium/tonic\"\ndescription = \"Prost codec implementation for tonic\"\nreadme = \"README.md\"\ncategories = [\"network-programming\", \"asynchronous\"]\nkeywords = [\"rpc\", \"grpc\", \"prost\", \"protobuf\", \"tonic\"]\nrust-version = { workspace = true }\n\n[dependencies]\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false }\nprost = \"0.14\"\nbytes = \"1\"\n\n[dev-dependencies]\ntokio = { version = \"1\", features = [\"macros\", \"rt-multi-thread\"] }\ntokio-stream = \"0.1\"\nhttp-body = \"1\"\nhttp-body-util = \"0.1\"\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  \"tonic::*\",\n  \"prost::*\",\n  \"prost\"\n]\n"
  },
  {
    "path": "tonic-prost/README.md",
    "content": "# tonic-prost\n\nProst codec implementation for [tonic] gRPC framework.\n\n## Overview\n\nThis crate provides the `ProstCodec` for encoding and decoding protobuf messages using the [prost] library.\n\n## Usage\n\nThis crate is typically used through the main `tonic` crate with the `prost` feature enabled (which is enabled by default).\n\n```toml\n[dependencies]\ntonic = \"0.14\"\n```\n\n[tonic]: https://github.com/hyperium/tonic\n[prost]: https://github.com/tokio-rs/prost"
  },
  {
    "path": "tonic-prost/src/codec.rs",
    "content": "use prost::Message;\nuse std::marker::PhantomData;\nuse tonic::Status;\nuse tonic::codec::{BufferSettings, Codec, DecodeBuf, Decoder, EncodeBuf, Encoder};\n\n/// A [`Codec`] that implements `application/grpc+proto` via the prost library.\n#[derive(Debug, Clone)]\npub struct ProstCodec<T, U> {\n    _pd: PhantomData<(T, U)>,\n}\n\nimpl<T, U> ProstCodec<T, U> {\n    /// Configure a ProstCodec with encoder/decoder buffer settings. This is used to control\n    /// how memory is allocated and grows per RPC.\n    pub fn new() -> Self {\n        Self { _pd: PhantomData }\n    }\n}\n\nimpl<T, U> Default for ProstCodec<T, U> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<T, U> ProstCodec<T, U>\nwhere\n    T: Message + Send + 'static,\n    U: Message + Default + Send + 'static,\n{\n    /// A tool for building custom codecs based on prost encoding and decoding.\n    /// See the codec_buffers example for one possible way to use this.\n    pub fn raw_encoder(buffer_settings: BufferSettings) -> <Self as Codec>::Encoder {\n        ProstEncoder {\n            _pd: PhantomData,\n            buffer_settings,\n        }\n    }\n\n    /// A tool for building custom codecs based on prost encoding and decoding.\n    /// See the codec_buffers example for one possible way to use this.\n    pub fn raw_decoder(buffer_settings: BufferSettings) -> <Self as Codec>::Decoder {\n        ProstDecoder {\n            _pd: PhantomData,\n            buffer_settings,\n        }\n    }\n}\n\nimpl<T, U> Codec for ProstCodec<T, U>\nwhere\n    T: Message + Send + 'static,\n    U: Message + Default + Send + 'static,\n{\n    type Encode = T;\n    type Decode = U;\n\n    type Encoder = ProstEncoder<T>;\n    type Decoder = ProstDecoder<U>;\n\n    fn encoder(&mut self) -> Self::Encoder {\n        ProstEncoder {\n            _pd: PhantomData,\n            buffer_settings: BufferSettings::default(),\n        }\n    }\n\n    fn decoder(&mut self) -> Self::Decoder {\n        ProstDecoder {\n            _pd: PhantomData,\n            buffer_settings: BufferSettings::default(),\n        }\n    }\n}\n\n/// A [`Encoder`] that knows how to encode `T`.\n#[derive(Debug, Clone, Default)]\npub struct ProstEncoder<T> {\n    _pd: PhantomData<T>,\n    buffer_settings: BufferSettings,\n}\n\nimpl<T> ProstEncoder<T> {\n    /// Get a new encoder with explicit buffer settings\n    pub fn new(buffer_settings: BufferSettings) -> Self {\n        Self {\n            _pd: PhantomData,\n            buffer_settings,\n        }\n    }\n}\n\nimpl<T: Message> Encoder for ProstEncoder<T> {\n    type Item = T;\n    type Error = Status;\n\n    fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> {\n        item.encode(buf)\n            .expect(\"Message only errors if not enough space\");\n\n        Ok(())\n    }\n\n    fn buffer_settings(&self) -> BufferSettings {\n        self.buffer_settings\n    }\n}\n\n/// A [`Decoder`] that knows how to decode `U`.\n#[derive(Debug, Clone, Default)]\npub struct ProstDecoder<U> {\n    _pd: PhantomData<U>,\n    buffer_settings: BufferSettings,\n}\n\nimpl<U> ProstDecoder<U> {\n    /// Get a new decoder with explicit buffer settings\n    pub fn new(buffer_settings: BufferSettings) -> Self {\n        Self {\n            _pd: PhantomData,\n            buffer_settings,\n        }\n    }\n}\n\nimpl<U: Message + Default> Decoder for ProstDecoder<U> {\n    type Item = U;\n    type Error = Status;\n\n    fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result<Option<Self::Item>, Self::Error> {\n        let item = Message::decode(buf)\n            .map(Option::Some)\n            .map_err(from_decode_error)?;\n\n        Ok(item)\n    }\n\n    fn buffer_settings(&self) -> BufferSettings {\n        self.buffer_settings\n    }\n}\n\nfn from_decode_error(error: prost::DecodeError) -> Status {\n    // Map Protobuf parse errors to an INTERNAL status code, as per\n    // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md\n    Status::internal(error.to_string())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use bytes::{Buf, BufMut, BytesMut};\n    use http_body::Body;\n    use http_body_util::BodyExt as _;\n    use std::pin::pin;\n    use tonic::codec::SingleMessageCompressionOverride;\n    use tonic::codec::{EncodeBody, HEADER_SIZE, Streaming};\n\n    const LEN: usize = 10000;\n    // The maximum uncompressed size in bytes for a message. Set to 2MB.\n    const MAX_MESSAGE_SIZE: usize = 2 * 1024 * 1024;\n\n    #[tokio::test]\n    async fn decode() {\n        let decoder = MockDecoder::default();\n\n        let msg = vec![0u8; LEN];\n\n        let mut buf = BytesMut::new();\n\n        buf.reserve(msg.len() + HEADER_SIZE);\n        buf.put_u8(0);\n        buf.put_u32(msg.len() as u32);\n\n        buf.put(&msg[..]);\n\n        let body = body::MockBody::new(&buf[..], 10005, 0);\n\n        let mut stream = Streaming::new_request(decoder, body, None, None);\n\n        let mut i = 0usize;\n        while let Some(output_msg) = stream.message().await.unwrap() {\n            assert_eq!(output_msg.len(), msg.len());\n            i += 1;\n        }\n        assert_eq!(i, 1);\n    }\n\n    #[tokio::test]\n    async fn decode_max_message_size_exceeded() {\n        let decoder = MockDecoder::default();\n\n        let msg = vec![0u8; MAX_MESSAGE_SIZE + 1];\n\n        let mut buf = BytesMut::new();\n\n        buf.reserve(msg.len() + HEADER_SIZE);\n        buf.put_u8(0);\n        buf.put_u32(msg.len() as u32);\n\n        buf.put(&msg[..]);\n\n        let body = body::MockBody::new(&buf[..], MAX_MESSAGE_SIZE + HEADER_SIZE + 1, 0);\n\n        let mut stream = Streaming::new_request(decoder, body, None, Some(MAX_MESSAGE_SIZE));\n\n        let actual = stream.message().await.unwrap_err();\n\n        let expected = Status::out_of_range(format!(\n            \"Error, decoded message length too large: found {} bytes, the limit is: {} bytes\",\n            msg.len(),\n            MAX_MESSAGE_SIZE\n        ));\n\n        assert_eq!(actual.code(), expected.code());\n        assert_eq!(actual.message(), expected.message());\n    }\n\n    #[tokio::test]\n    async fn encode() {\n        let encoder = MockEncoder::default();\n\n        let msg = Vec::from(&[0u8; 1024][..]);\n\n        let messages = std::iter::repeat_with(move || Ok::<_, Status>(msg.clone())).take(10000);\n        let source = tokio_stream::iter(messages);\n\n        let mut body = pin!(EncodeBody::new_server(\n            encoder,\n            source,\n            None,\n            SingleMessageCompressionOverride::default(),\n            None,\n        ));\n\n        while let Some(r) = body.frame().await {\n            r.unwrap();\n        }\n    }\n\n    #[tokio::test]\n    async fn encode_max_message_size_exceeded() {\n        let encoder = MockEncoder::default();\n\n        let msg = vec![0u8; MAX_MESSAGE_SIZE + 1];\n\n        let messages = std::iter::once(Ok::<_, Status>(msg));\n        let source = tokio_stream::iter(messages);\n\n        let mut body = pin!(EncodeBody::new_server(\n            encoder,\n            source,\n            None,\n            SingleMessageCompressionOverride::default(),\n            Some(MAX_MESSAGE_SIZE),\n        ));\n\n        let frame = body\n            .frame()\n            .await\n            .expect(\"at least one frame\")\n            .expect(\"no error polling frame\");\n        assert_eq!(\n            frame\n                .into_trailers()\n                .expect(\"got trailers\")\n                .get(Status::GRPC_STATUS)\n                .expect(\"grpc-status header\"),\n            \"11\"\n        );\n        assert!(body.is_end_stream());\n    }\n\n    // skip on windows because CI stumbles over our 4GB allocation\n    #[cfg(not(target_family = \"windows\"))]\n    #[tokio::test]\n    async fn encode_too_big() {\n        let encoder = MockEncoder::default();\n\n        let msg = vec![0u8; u32::MAX as usize + 1];\n\n        let messages = std::iter::once(Ok::<_, Status>(msg));\n        let source = tokio_stream::iter(messages);\n\n        let mut body = pin!(EncodeBody::new_server(\n            encoder,\n            source,\n            None,\n            SingleMessageCompressionOverride::default(),\n            Some(usize::MAX),\n        ));\n\n        let frame = body\n            .frame()\n            .await\n            .expect(\"at least one frame\")\n            .expect(\"no error polling frame\");\n        assert_eq!(\n            frame\n                .into_trailers()\n                .expect(\"got trailers\")\n                .get(Status::GRPC_STATUS)\n                .expect(\"grpc-status header\"),\n            \"8\"\n        );\n        assert!(body.is_end_stream());\n    }\n\n    #[derive(Debug, Clone, Default)]\n    struct MockEncoder {}\n\n    impl Encoder for MockEncoder {\n        type Item = Vec<u8>;\n        type Error = Status;\n\n        fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> {\n            buf.put(&item[..]);\n            Ok(())\n        }\n\n        fn buffer_settings(&self) -> BufferSettings {\n            Default::default()\n        }\n    }\n\n    #[derive(Debug, Clone, Default)]\n    struct MockDecoder {}\n\n    impl Decoder for MockDecoder {\n        type Item = Vec<u8>;\n        type Error = Status;\n\n        fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result<Option<Self::Item>, Self::Error> {\n            let out = Vec::from(buf.chunk());\n            buf.advance(LEN);\n            Ok(Some(out))\n        }\n\n        fn buffer_settings(&self) -> BufferSettings {\n            Default::default()\n        }\n    }\n\n    mod body {\n        use bytes::Bytes;\n        use http_body::{Body, Frame};\n        use std::{\n            pin::Pin,\n            task::{Context, Poll},\n        };\n        use tonic::Status;\n\n        #[derive(Debug)]\n        pub(super) struct MockBody {\n            data: Bytes,\n\n            // the size of the partial message to send\n            partial_len: usize,\n\n            // the number of times we've sent\n            count: usize,\n        }\n\n        impl MockBody {\n            pub(super) fn new(b: &[u8], partial_len: usize, count: usize) -> Self {\n                MockBody {\n                    data: Bytes::copy_from_slice(b),\n                    partial_len,\n                    count,\n                }\n            }\n        }\n\n        impl Body for MockBody {\n            type Data = Bytes;\n            type Error = Status;\n\n            fn poll_frame(\n                mut self: Pin<&mut Self>,\n                cx: &mut Context<'_>,\n            ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n                // every other call to poll_data returns data\n                let should_send = self.count % 2 == 0;\n                let data_len = self.data.len();\n                let partial_len = self.partial_len;\n                let count = self.count;\n                if data_len > 0 {\n                    let result = if should_send {\n                        let response =\n                            self.data\n                                .split_to(if count == 0 { partial_len } else { data_len });\n                        Poll::Ready(Some(Ok(Frame::data(response))))\n                    } else {\n                        cx.waker().wake_by_ref();\n                        Poll::Pending\n                    };\n                    // make some fake progress\n                    self.count += 1;\n                    result\n                } else {\n                    Poll::Ready(None)\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-prost/src/lib.rs",
    "content": "//! Prost codec implementation for tonic.\n//!\n//! This crate provides the [`ProstCodec`] for encoding and decoding protobuf\n//! messages using the [`prost`] library.\n//!\n//! # Example\n//!\n//! ```rust,ignore\n//! use tonic_prost::ProstCodec;\n//!\n//! let codec = ProstCodec::<Message, Message>::default();\n//! ```\n\n#![warn(\n    missing_docs,\n    missing_debug_implementations,\n    rust_2018_idioms,\n    unreachable_pub\n)]\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg\"\n)]\n#![doc(html_root_url = \"https://docs.rs/tonic-prost/0.13.1\")]\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n\nmod codec;\n\npub use codec::{ProstCodec, ProstDecoder, ProstEncoder};\n\n// Re-export prost types that users might need\npub use prost;\n"
  },
  {
    "path": "tonic-prost-build/Cargo.toml",
    "content": "[package]\nname = \"tonic-prost-build\"\nversion = \"0.14.5\"\nauthors = [\"Lucio Franco <luciofranco14@gmail.com>\"]\nedition = \"2024\"\nlicense = \"MIT\"\nrepository = \"https://github.com/hyperium/tonic\"\nhomepage = \"https://github.com/hyperium/tonic\"\ndescription = \"Prost build integration for tonic\"\nreadme = \"README.md\"\ncategories = [\"development-tools::build-utils\", \"network-programming\", \"asynchronous\"]\nkeywords = [\"rpc\", \"grpc\", \"prost\", \"protobuf\", \"tonic\"]\nrust-version = { workspace = true }\n\n[features]\ndefault = [\"transport\", \"cleanup-markdown\"]\ntransport = [\"tonic-build/transport\"]\ncleanup-markdown = [\"prost-build/cleanup-markdown\"]\n\n[dependencies]\ntonic-build = { version = \"0.14.0\", path = \"../tonic-build\", default-features = false }\nprost-build = { version = \"0.14\" }\nprost-types = { version = \"0.14\" }\nprettyplease = { version = \"0.2\" }\nproc-macro2 = \"1.0\"\nquote = \"1.0\"\nsyn = \"2.0\"\ntempfile = \"3.0\"\n\n[dev-dependencies]\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false }\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  \"tonic_build::*\",\n  \"prost_build::*\",\n  \"prost_types::*\"\n]\n"
  },
  {
    "path": "tonic-prost-build/README.md",
    "content": "# tonic-prost-build\n\nProst build integration for [tonic] gRPC framework.\n\n## Overview\n\nThis crate provides code generation for gRPC services using protobuf definitions via the [prost] ecosystem. It bridges [prost-build] with [tonic]'s generic code generation infrastructure.\n\n## Usage\n\nAdd to your `build.rs`:\n\n```rust\nfn main() {\n    tonic_prost_build::configure()\n        .compile_protos(&[\"proto/service.proto\"], &[\"proto\"])\n        .unwrap();\n}\n```\n\n## Features\n\n- `transport`: Enables transport layer code generation\n- `cleanup-markdown`: Enables markdown cleanup in generated documentation\n\n[tonic]: https://github.com/hyperium/tonic\n[prost]: https://github.com/tokio-rs/prost\n[prost-build]: https://github.com/tokio-rs/prost"
  },
  {
    "path": "tonic-prost-build/src/lib.rs",
    "content": "//! Prost build integration for tonic.\n//!\n//! This crate provides code generation for gRPC services using protobuf definitions\n//! via the [`prost`] ecosystem.\n//!\n//! [`prost`]: https://github.com/tokio-rs/prost\n//!\n//! # Example\n//!\n//! ```rust,ignore\n//! use tonic_prost_build::configure;\n//!\n//! fn main() {\n//!     configure()\n//!         .compile_protos(&[\"proto/service.proto\"], &[\"proto\"])\n//!         .unwrap();\n//! }\n//! ```\n\n#![warn(\n    missing_docs,\n    missing_debug_implementations,\n    rust_2018_idioms,\n    unreachable_pub\n)]\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg\"\n)]\n#![doc(html_root_url = \"https://docs.rs/tonic-prost-build/0.14.0\")]\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n\nuse proc_macro2::TokenStream;\nuse prost_build::{Method, Service};\nuse quote::{ToTokens, quote};\nuse std::cell::RefCell;\nuse std::{\n    collections::HashSet,\n    ffi::OsString,\n    io,\n    path::{Path, PathBuf},\n};\nuse tonic_build::{Attributes, CodeGenBuilder};\n\n#[cfg(test)]\nmod tests;\n\n// Re-export core build functionality from tonic-build\npub use tonic_build::{\n    Attributes as TonicAttributes, Method as TonicMethod, Service as TonicService, manual,\n};\n\n// Re-export prost types that users might need\npub use prost_build::Config;\npub use prost_types::FileDescriptorSet;\n\n/// Configure `tonic-prost-build` code generation.\n///\n/// Use [`compile_protos`] instead if you don't need to tweak anything.\npub fn configure() -> Builder {\n    Builder {\n        build_client: true,\n        build_server: true,\n        build_transport: true,\n        file_descriptor_set_path: None,\n        skip_protoc_run: false,\n        out_dir: None,\n        extern_path: Vec::new(),\n        field_attributes: Vec::new(),\n        message_attributes: Vec::new(),\n        enum_attributes: Vec::new(),\n        type_attributes: Vec::new(),\n        boxed: Vec::new(),\n        btree_map: None,\n        bytes: None,\n        server_attributes: Attributes::default(),\n        client_attributes: Attributes::default(),\n        proto_path: \"super\".to_string(),\n        compile_well_known_types: false,\n        emit_package: true,\n        with_extended_rust_types: false,\n        protoc_args: Vec::new(),\n        include_file: None,\n        emit_rerun_if_changed: std::env::var_os(\"CARGO\").is_some(),\n        disable_comments: HashSet::default(),\n        use_arc_self: false,\n        generate_default_stubs: false,\n        codec_path: \"tonic_prost::ProstCodec\".to_string(),\n        skip_debug: HashSet::default(),\n    }\n}\n\n/// Simple `.proto` compiling. Use [`configure`] instead if you need more options.\n///\n/// The include directory will be the parent folder of the specified path.\n/// The package name will be the filename without the extension.\npub fn compile_protos(proto: impl AsRef<Path>) -> io::Result<()> {\n    let proto_path: &Path = proto.as_ref();\n\n    // directory the main .proto file resides in\n    let proto_dir = proto_path\n        .parent()\n        .expect(\"proto file should reside in a directory\");\n\n    self::configure().compile_protos(&[proto_path], &[proto_dir])\n}\n\n/// Simple file descriptor set compiling. Use [`configure`] instead if you need more options.\npub fn compile_fds(fds: prost_types::FileDescriptorSet) -> io::Result<()> {\n    self::configure().compile_fds(fds)\n}\n\n/// Extended list of Non-path Rust types allowed for request/response types.\n/// Needed for compiling well known types as request/responses.\nconst EXTENDED_NON_PATH_TYPE_ALLOWLIST: &[&str] =\n    &[\"()\", \"bool\", \"i32\", \"i64\", \"u32\", \"u64\", \"f32\", \"f64\"];\n/// List of Non-path Rust types allowed for request/response types.\nconst DEFAULT_NON_PATH_TYPE_ALLOWLIST: &[&str] = &[\"()\"];\n\nthread_local! {\n    /// Chosen allowlist, which would be [`EXTENDED_NON_PATH_TYPE_ALLOWLIST`] if\n    /// [`Builder::with_extended_rust_types`] was called.\n    pub static NON_PATH_TYPE_ALLOWLIST: RefCell<&'static [&'static str]> = const {\n        RefCell::new(DEFAULT_NON_PATH_TYPE_ALLOWLIST)\n    };\n}\n\n/// Newtype wrapper for prost to add tonic-specific extensions\nstruct TonicBuildService {\n    prost_service: Service,\n    methods: Vec<TonicBuildMethod>,\n}\n\nimpl TonicBuildService {\n    fn new(prost_service: Service, codec_path: String) -> Self {\n        Self {\n            // The tonic_build::Service trait specifies that methods are borrowed, so they have to reified up front.\n            methods: prost_service\n                .methods\n                .iter()\n                .map(|prost_method| TonicBuildMethod {\n                    prost_method: prost_method.clone(),\n                    codec_path: codec_path.clone(),\n                })\n                .collect(),\n            prost_service,\n        }\n    }\n}\n\n/// Newtype wrapper for prost to add tonic-specific extensions\nstruct TonicBuildMethod {\n    prost_method: Method,\n    codec_path: String,\n}\n\nimpl tonic_build::Service for TonicBuildService {\n    type Method = TonicBuildMethod;\n    type Comment = String;\n\n    fn name(&self) -> &str {\n        &self.prost_service.name\n    }\n\n    fn package(&self) -> &str {\n        &self.prost_service.package\n    }\n\n    fn identifier(&self) -> &str {\n        &self.prost_service.proto_name\n    }\n\n    fn methods(&self) -> &[Self::Method] {\n        &self.methods\n    }\n\n    fn comment(&self) -> &[Self::Comment] {\n        &self.prost_service.comments.leading\n    }\n}\n\nimpl tonic_build::Method for TonicBuildMethod {\n    type Comment = String;\n\n    fn name(&self) -> &str {\n        &self.prost_method.name\n    }\n\n    fn identifier(&self) -> &str {\n        &self.prost_method.proto_name\n    }\n\n    fn client_streaming(&self) -> bool {\n        self.prost_method.client_streaming\n    }\n\n    fn server_streaming(&self) -> bool {\n        self.prost_method.server_streaming\n    }\n\n    fn comment(&self) -> &[Self::Comment] {\n        &self.prost_method.comments.leading\n    }\n\n    fn request_response_name(\n        &self,\n        proto_path: &str,\n        compile_well_known_types: bool,\n    ) -> (TokenStream, TokenStream) {\n        let request = if is_google_type(&self.prost_method.input_type) && !compile_well_known_types\n        {\n            // For well-known types, map to absolute paths that will work with super::\n            match self.prost_method.input_type.as_str() {\n                \".google.protobuf.Empty\" => quote!(()),\n                \".google.protobuf.Any\" => quote!(::prost_types::Any),\n                \".google.protobuf.StringValue\" => quote!(::prost::alloc::string::String),\n                _ => {\n                    // For other google types, assume they're in prost_types\n                    let type_name = self\n                        .prost_method\n                        .input_type\n                        .trim_start_matches(\".google.protobuf.\")\n                        .to_string();\n                    syn::parse_str::<syn::Path>(&format!(\"::prost_types::{type_name}\"))\n                        .unwrap()\n                        .to_token_stream()\n                }\n            }\n        } else if is_non_path_type(&self.prost_method.input_type) {\n            self.prost_method.input_type.parse::<TokenStream>().unwrap()\n        } else {\n            // Check if this is an extern type that starts with :: or crate::\n            if self.prost_method.input_type.starts_with(\"::\")\n                || self.prost_method.input_type.starts_with(\"crate::\")\n            {\n                // This is an extern type, use it directly\n                self.prost_method.input_type.parse::<TokenStream>().unwrap()\n            } else {\n                // Replace dots with double colons for the type name\n                let rust_type = self.prost_method.input_type.replace('.', \"::\");\n                // Remove leading :: if present\n                let rust_type = rust_type.trim_start_matches(\"::\");\n                syn::parse_str::<syn::Path>(&format!(\"{proto_path}::{rust_type}\"))\n                    .unwrap()\n                    .to_token_stream()\n            }\n        };\n\n        let response =\n            if is_google_type(&self.prost_method.output_type) && !compile_well_known_types {\n                // For well-known types, map to absolute paths that will work with super::\n                match self.prost_method.output_type.as_str() {\n                    \".google.protobuf.Empty\" => quote!(()),\n                    \".google.protobuf.Any\" => quote!(::prost_types::Any),\n                    \".google.protobuf.StringValue\" => quote!(::prost::alloc::string::String),\n                    _ => {\n                        // For other google types, assume they're in prost_types\n                        let type_name = self\n                            .prost_method\n                            .output_type\n                            .trim_start_matches(\".google.protobuf.\")\n                            .to_string();\n                        syn::parse_str::<syn::Path>(&format!(\"::prost_types::{type_name}\"))\n                            .unwrap()\n                            .to_token_stream()\n                    }\n                }\n            } else if is_non_path_type(&self.prost_method.output_type) {\n                self.prost_method\n                    .output_type\n                    .parse::<TokenStream>()\n                    .unwrap()\n            } else {\n                // Check if this is an extern type that starts with :: or crate::\n                if self.prost_method.output_type.starts_with(\"::\")\n                    || self.prost_method.output_type.starts_with(\"crate::\")\n                {\n                    // This is an extern type, use it directly\n                    self.prost_method\n                        .output_type\n                        .parse::<TokenStream>()\n                        .unwrap()\n                } else {\n                    // Replace dots with double colons for the type name\n                    let rust_type = self.prost_method.output_type.replace('.', \"::\");\n                    // Remove leading :: if present\n                    let rust_type = rust_type.trim_start_matches(\"::\");\n                    syn::parse_str::<syn::Path>(&format!(\"{proto_path}::{rust_type}\"))\n                        .unwrap()\n                        .to_token_stream()\n                }\n            };\n\n        (request, response)\n    }\n\n    fn codec_path(&self) -> &str {\n        &self.codec_path\n    }\n\n    fn deprecated(&self) -> bool {\n        self.prost_method.options.deprecated()\n    }\n}\n\nfn is_non_path_type(ty: &str) -> bool {\n    NON_PATH_TYPE_ALLOWLIST.with(|allowlist| {\n        allowlist\n            .borrow()\n            .iter()\n            .any(|allowlist_type| ty.ends_with(allowlist_type))\n    })\n}\n\nfn is_google_type(ty: &str) -> bool {\n    ty.starts_with(\".google.protobuf\")\n}\n\n/// Service generator that is compatible with prost-build\n#[derive(Debug)]\nstruct ServiceGenerator {\n    build_client: bool,\n    build_server: bool,\n    build_transport: bool,\n    client_attributes: Attributes,\n    server_attributes: Attributes,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n    proto_path: String,\n    compile_well_known_types: bool,\n    codec_path: String,\n    disable_comments: HashSet<String>,\n}\n\nimpl ServiceGenerator {\n    /// Create a new ServiceGenerator\n    #[allow(clippy::too_many_arguments)]\n    fn new(\n        build_client: bool,\n        build_server: bool,\n        build_transport: bool,\n        client_attributes: Attributes,\n        server_attributes: Attributes,\n        use_arc_self: bool,\n        generate_default_stubs: bool,\n        proto_path: String,\n        compile_well_known_types: bool,\n        codec_path: String,\n        disable_comments: HashSet<String>,\n    ) -> Self {\n        ServiceGenerator {\n            build_client,\n            build_server,\n            build_transport,\n            client_attributes,\n            server_attributes,\n            use_arc_self,\n            generate_default_stubs,\n            proto_path,\n            compile_well_known_types,\n            codec_path,\n            disable_comments,\n        }\n    }\n}\n\nimpl prost_build::ServiceGenerator for ServiceGenerator {\n    fn generate(&mut self, service: Service, buf: &mut String) {\n        let tonic_service = TonicBuildService::new(service, self.codec_path.clone());\n\n        let mut builder = CodeGenBuilder::new();\n        builder\n            .emit_package(true)\n            .build_transport(self.build_transport)\n            .compile_well_known_types(self.compile_well_known_types)\n            .disable_comments(self.disable_comments.clone())\n            .use_arc_self(self.use_arc_self)\n            .generate_default_stubs(self.generate_default_stubs);\n\n        let mut tokens = TokenStream::new();\n\n        if self.build_client {\n            builder.attributes(self.client_attributes.clone());\n            let client_code = builder.generate_client(&tonic_service, &self.proto_path);\n            tokens.extend(client_code);\n        }\n\n        if self.build_server {\n            builder.attributes(self.server_attributes.clone());\n            let server_code = builder.generate_server(&tonic_service, &self.proto_path);\n            tokens.extend(server_code);\n        }\n\n        let formatted = prettyplease::unparse(&syn::parse2(tokens).unwrap());\n        buf.push_str(&formatted);\n    }\n}\n\n/// Builder for configuring and generating code from `.proto` files.\n#[derive(Debug, Clone)]\npub struct Builder {\n    build_client: bool,\n    build_server: bool,\n    build_transport: bool,\n    file_descriptor_set_path: Option<PathBuf>,\n    skip_protoc_run: bool,\n    out_dir: Option<PathBuf>,\n    extern_path: Vec<(String, String)>,\n    field_attributes: Vec<(String, String)>,\n    message_attributes: Vec<(String, String)>,\n    enum_attributes: Vec<(String, String)>,\n    type_attributes: Vec<(String, String)>,\n    boxed: Vec<String>,\n    btree_map: Option<Vec<String>>,\n    bytes: Option<Vec<String>>,\n    server_attributes: Attributes,\n    client_attributes: Attributes,\n    proto_path: String,\n    compile_well_known_types: bool,\n    emit_package: bool,\n    with_extended_rust_types: bool,\n    protoc_args: Vec<OsString>,\n    include_file: Option<PathBuf>,\n    emit_rerun_if_changed: bool,\n    disable_comments: HashSet<String>,\n    use_arc_self: bool,\n    generate_default_stubs: bool,\n    codec_path: String,\n    skip_debug: HashSet<String>,\n}\n\nimpl Builder {\n    /// Enable or disable gRPC client code generation.\n    pub fn build_client(mut self, enable: bool) -> Self {\n        self.build_client = enable;\n        self\n    }\n\n    /// Enable or disable gRPC server code generation.\n    pub fn build_server(mut self, enable: bool) -> Self {\n        self.build_server = enable;\n        self\n    }\n\n    /// Enable or disable transport-related features.\n    pub fn build_transport(mut self, enable: bool) -> Self {\n        self.build_transport = enable;\n        self\n    }\n\n    /// Configure the output directory where generated Rust files are written.\n    ///\n    /// If unset, defaults to the `OUT_DIR` environment variable. `OUT_DIR` is set by Cargo when\n    /// executing build scripts, so `out_dir` typically does not need to be configured.\n    pub fn out_dir(mut self, out_dir: impl AsRef<Path>) -> Self {\n        self.out_dir = Some(out_dir.as_ref().to_path_buf());\n        self\n    }\n\n    /// Declare externally provided Protobuf package or type.\n    ///\n    /// Passed directly to `prost_build::Config.extern_path`.\n    /// Note that both the Protobuf path and the rust package paths should both be fully qualified.\n    /// i.e. Protobuf path should start with \".\" and rust path should start with \"::\"\n    pub fn extern_path(mut self, proto_path: impl AsRef<str>, rust_path: impl AsRef<str>) -> Self {\n        self.extern_path.push((\n            proto_path.as_ref().to_string(),\n            rust_path.as_ref().to_string(),\n        ));\n        self\n    }\n\n    /// Add additional attribute to matched messages, enums, and one-offs.\n    ///\n    /// Passed directly to `prost_build::Config.field_attribute`.\n    pub fn field_attribute<P: AsRef<str>, A: AsRef<str>>(mut self, path: P, attribute: A) -> Self {\n        self.field_attributes\n            .push((path.as_ref().to_string(), attribute.as_ref().to_string()));\n        self\n    }\n\n    /// Add additional attribute to matched messages, enums, and one-offs.\n    ///\n    /// Passed directly to `prost_build::Config.message_attribute`.\n    pub fn message_attribute<P: AsRef<str>, A: AsRef<str>>(\n        mut self,\n        path: P,\n        attribute: A,\n    ) -> Self {\n        self.message_attributes\n            .push((path.as_ref().to_string(), attribute.as_ref().to_string()));\n        self\n    }\n\n    /// Add additional attribute to matched enums and one-offs.\n    ///\n    /// Passed directly to `prost_build::Config.enum_attribute`.\n    pub fn enum_attribute<P: AsRef<str>, A: AsRef<str>>(mut self, path: P, attribute: A) -> Self {\n        self.enum_attributes\n            .push((path.as_ref().to_string(), attribute.as_ref().to_string()));\n        self\n    }\n\n    /// Add additional attribute to matched messages, enums, and one-offs.\n    ///\n    /// Passed directly to `prost_build::Config.type_attribute`.\n    pub fn type_attribute<P: AsRef<str>, A: AsRef<str>>(mut self, path: P, attribute: A) -> Self {\n        self.type_attributes\n            .push((path.as_ref().to_string(), attribute.as_ref().to_string()));\n        self\n    }\n\n    /// Add a field that should be boxed.\n    ///\n    /// Passed directly to `prost_build::Config.boxed`.\n    pub fn boxed<P: AsRef<str>>(mut self, path: P) -> Self {\n        self.boxed.push(path.as_ref().to_string());\n        self\n    }\n\n    /// Configure btree_map on a message.\n    ///\n    /// Passed directly to `prost_build::Config.btree_map`.\n    pub fn btree_map<P: AsRef<str>>(mut self, path: P) -> Self {\n        match &mut self.btree_map {\n            Some(paths) => paths.push(path.as_ref().to_string()),\n            None => self.btree_map = Some(vec![path.as_ref().to_string()]),\n        }\n        self\n    }\n\n    /// Configure bytes on a message.\n    ///\n    /// Passed directly to `prost_build::Config.bytes`.\n    pub fn bytes<P: AsRef<str>>(mut self, path: P) -> Self {\n        match &mut self.bytes {\n            Some(paths) => paths.push(path.as_ref().to_string()),\n            None => self.bytes = Some(vec![path.as_ref().to_string()]),\n        }\n        self\n    }\n\n    /// Add additional attribute to matched server `mod`s. Passed directly to\n    /// `prost_build::Config.message_attribute`\n    pub fn server_mod_attribute<P: AsRef<str>, A: AsRef<str>>(\n        mut self,\n        path: P,\n        attribute: A,\n    ) -> Self {\n        self.server_attributes\n            .push_mod(path.as_ref(), attribute.as_ref());\n        self\n    }\n\n    /// Add additional attribute to matched service servers. Passed directly to\n    /// `prost_build::Config.message_attribute`\n    pub fn server_attribute<P: AsRef<str>, A: AsRef<str>>(mut self, path: P, attribute: A) -> Self {\n        self.server_attributes\n            .push_struct(path.as_ref(), attribute.as_ref());\n        self\n    }\n\n    /// Add additional attribute to matched traits. Passed directly to\n    /// `prost_build::Config.message_attribute`\n    pub fn trait_attribute<P: AsRef<str>, A: AsRef<str>>(mut self, path: P, attribute: A) -> Self {\n        self.server_attributes\n            .push_trait(path.as_ref(), attribute.as_ref());\n        self\n    }\n\n    /// Add additional attribute to matched client `mod`s. Passed directly to\n    /// `prost_build::Config.message_attribute`\n    pub fn client_mod_attribute<P: AsRef<str>, A: AsRef<str>>(\n        mut self,\n        path: P,\n        attribute: A,\n    ) -> Self {\n        self.client_attributes\n            .push_mod(path.as_ref(), attribute.as_ref());\n        self\n    }\n\n    /// Add additional attribute to matched service clients. Passed directly to\n    /// `prost_build::Config.message_attribute`\n    pub fn client_attribute<P: AsRef<str>, A: AsRef<str>>(mut self, path: P, attribute: A) -> Self {\n        self.client_attributes\n            .push_struct(path.as_ref(), attribute.as_ref());\n        self\n    }\n\n    /// Set the path to where protobuf types are generated in the module tree.\n    /// Default is `super`.\n    ///\n    /// This should be used in combination with `extern_path` when you want to use types that are\n    /// defined in other crates or modules, since types generated with `.proto_path(\"my_types\")`\n    /// will be at the path `my_types::generated_package_name`.\n    ///\n    /// This will change the path that is used to include the generated types, for example:\n    /// - `my_package::my_type` (default `proto_path`)\n    /// - `my_types::my_package::my_type` (with `proto_path(\"my_types\")`)\n    ///\n    /// Use `.extern_path(\"my.package\", \"::my_types::my_package\")` to use the generated types.\n    pub fn proto_path(mut self, proto_path: impl AsRef<str>) -> Self {\n        self.proto_path = proto_path.as_ref().to_string();\n        self\n    }\n\n    /// Enable or disable directing Protobuf to compile well-known types.\n    ///\n    /// Passed directly to `prost_build::Config.compile_well_known_types`.\n    pub fn compile_well_known_types(mut self, enable: bool) -> Self {\n        self.compile_well_known_types = enable;\n        self\n    }\n\n    /// Use the extended mapping of well-known types to rust types.\n    ///\n    /// Default is `false`.\n    pub fn with_extended_rust_types(mut self, enable: bool) -> Self {\n        self.with_extended_rust_types = enable;\n        self\n    }\n\n    /// Enable or disable emitting package information.\n    ///\n    /// Passed directly to `prost_build::Config.emit_package`.\n    pub fn emit_package(mut self, enable: bool) -> Self {\n        self.emit_package = enable;\n        self\n    }\n\n    /// Set the output file's path, used to write the file descriptor set.\n    ///\n    /// Passed directly to `prost_build::Config.file_descriptor_set_path`.\n    pub fn file_descriptor_set_path(mut self, path: impl AsRef<Path>) -> Self {\n        self.file_descriptor_set_path = Some(path.as_ref().to_path_buf());\n        self\n    }\n\n    /// Skip building protos and just generate code using the provided file descriptor set.\n    ///\n    /// Passed directly to `prost_build::Config.skip_protoc_run`.\n    pub fn skip_protoc_run(mut self) -> Self {\n        self.skip_protoc_run = true;\n        self\n    }\n\n    /// Add additional protoc arguments.\n    ///\n    /// Passed directly to `prost_build::Config.protoc_arg`.\n    pub fn protoc_arg<A: AsRef<str>>(mut self, arg: A) -> Self {\n        self.protoc_args.push(arg.as_ref().into());\n        self\n    }\n\n    /// Set the include file.\n    ///\n    /// Passed directly to `prost_build::Config.include_file`.\n    pub fn include_file(mut self, path: impl AsRef<Path>) -> Self {\n        self.include_file = Some(path.as_ref().to_path_buf());\n        self\n    }\n\n    /// Controls the generation of `include!` statements in the output files.\n    ///\n    /// Passed directly to `prost_build::Config.emit_rerun_if_changed`.\n    pub fn emit_rerun_if_changed(mut self, enable: bool) -> Self {\n        self.emit_rerun_if_changed = enable;\n        self\n    }\n\n    /// Set the comments that should be disabled.\n    ///\n    /// Passed directly to `prost_build::Config.disable_comments`.\n    pub fn disable_comments<I, S>(mut self, path: I) -> Self\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<str>,\n    {\n        self.disable_comments\n            .extend(path.into_iter().map(|s| s.as_ref().to_string()));\n        self\n    }\n\n    /// Use `Arc<Self>` on the Server trait.\n    pub fn use_arc_self(mut self, enable: bool) -> Self {\n        self.use_arc_self = enable;\n        self\n    }\n\n    /// Generate the default stubs for gRPC services. This code will be generated\n    /// inside of your service module. Ex: `pub mod helloworld { ... }`\n    pub fn generate_default_stubs(mut self, enable: bool) -> Self {\n        self.generate_default_stubs = enable;\n        self\n    }\n\n    /// Set the codec path for generated gRPC services.\n    pub fn codec_path(mut self, path: impl AsRef<str>) -> Self {\n        self.codec_path = path.as_ref().to_string();\n        self\n    }\n\n    /// Configure the code generator not to strip the `Debug` implementation for the request and\n    /// response types from the generated code.\n    ///\n    /// Passed directly to `prost_build::Config.skip_debug`.\n    pub fn skip_debug<I, S>(mut self, paths: I) -> Self\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<str>,\n    {\n        self.skip_debug\n            .extend(paths.into_iter().map(|s| s.as_ref().to_string()));\n        self\n    }\n\n    /// Compile the .proto files and execute code generation.\n    pub fn compile_protos<P>(self, protos: &[P], includes: &[P]) -> io::Result<()>\n    where\n        P: AsRef<Path>,\n    {\n        self.compile_with_config(Config::new(), protos, includes)\n    }\n\n    /// Compile the .proto files and execute code generation with a custom `prost_build::Config`.\n    ///\n    /// Note: When using a custom config, any disable_comments settings on the Builder will be ignored\n    /// to preserve the disable_comments already configured on the provided Config.\n    pub fn compile_with_config<P>(\n        self,\n        mut config: Config,\n        protos: &[P],\n        includes: &[P],\n    ) -> io::Result<()>\n    where\n        P: AsRef<Path>,\n    {\n        /// Drop guard that will set [`NON_PATH_TYPE_ALLOWLIST`] back\n        /// to its default on exit.\n        struct Defer;\n        impl Drop for Defer {\n            fn drop(&mut self) {\n                NON_PATH_TYPE_ALLOWLIST.set(DEFAULT_NON_PATH_TYPE_ALLOWLIST);\n            }\n        }\n\n        let _defer_guard = Defer;\n\n        let out_dir = if let Some(out_dir) = self.out_dir.as_ref() {\n            out_dir.clone()\n        } else {\n            PathBuf::from(std::env::var(\"OUT_DIR\").unwrap())\n        };\n\n        config.out_dir(&out_dir);\n\n        for (proto_path, rust_path) in &self.extern_path {\n            config.extern_path(proto_path, rust_path);\n        }\n\n        for (prost_path, attr) in &self.field_attributes {\n            config.field_attribute(prost_path, attr);\n        }\n\n        for (prost_path, attr) in &self.message_attributes {\n            config.message_attribute(prost_path, attr);\n        }\n\n        for (prost_path, attr) in &self.enum_attributes {\n            config.enum_attribute(prost_path, attr);\n        }\n\n        for (prost_path, attr) in &self.type_attributes {\n            config.type_attribute(prost_path, attr);\n        }\n\n        for prost_path in &self.boxed {\n            config.boxed(prost_path);\n        }\n\n        if let Some(ref paths) = self.btree_map {\n            config.btree_map(paths);\n        }\n\n        if let Some(ref paths) = self.bytes {\n            config.bytes(paths);\n        }\n\n        if self.compile_well_known_types {\n            config.compile_well_known_types();\n        }\n\n        for arg in &self.protoc_args {\n            config.protoc_arg(arg);\n        }\n\n        if let Some(path) = &self.include_file {\n            config.include_file(path);\n        }\n\n        if self.with_extended_rust_types {\n            NON_PATH_TYPE_ALLOWLIST.set(EXTENDED_NON_PATH_TYPE_ALLOWLIST);\n        }\n\n        // Note: We don't pass self.disable_comments to prost Config here\n        // because those are meant for service/method paths which are handled\n        // by the ServiceGenerator, not for message paths\n\n        if !self.skip_debug.is_empty() {\n            config.skip_debug(self.skip_debug.clone());\n        }\n\n        if let Some(path) = &self.file_descriptor_set_path {\n            config.file_descriptor_set_path(path);\n        }\n\n        if self.skip_protoc_run {\n            config.skip_protoc_run();\n        }\n\n        if self.build_client || self.build_server {\n            let service_generator = ServiceGenerator::new(\n                self.build_client,\n                self.build_server,\n                self.build_transport,\n                self.client_attributes,\n                self.server_attributes,\n                self.use_arc_self,\n                self.generate_default_stubs,\n                self.proto_path,\n                self.compile_well_known_types,\n                self.codec_path.clone(),\n                self.disable_comments,\n            );\n\n            config.service_generator(Box::new(service_generator));\n        };\n\n        config.compile_protos(protos, includes)?;\n\n        Ok(())\n    }\n\n    /// Compile a [`prost_types::FileDescriptorSet`] and execute code generation.\n    pub fn compile_fds(self, fds: prost_types::FileDescriptorSet) -> io::Result<()> {\n        self.compile_fds_with_config(fds, Config::new())\n    }\n\n    /// Compile a [`prost_types::FileDescriptorSet`] with a custom `prost_build::Config`.\n    pub fn compile_fds_with_config(\n        self,\n        fds: prost_types::FileDescriptorSet,\n        mut config: Config,\n    ) -> io::Result<()> {\n        let out_dir = if let Some(out_dir) = self.out_dir.as_ref() {\n            out_dir.clone()\n        } else {\n            PathBuf::from(std::env::var(\"OUT_DIR\").unwrap())\n        };\n\n        config.out_dir(&out_dir);\n\n        for (proto_path, rust_path) in &self.extern_path {\n            config.extern_path(proto_path, rust_path);\n        }\n\n        for (prost_path, attr) in &self.field_attributes {\n            config.field_attribute(prost_path, attr);\n        }\n\n        for (prost_path, attr) in &self.message_attributes {\n            config.message_attribute(prost_path, attr);\n        }\n\n        for (prost_path, attr) in &self.enum_attributes {\n            config.enum_attribute(prost_path, attr);\n        }\n\n        for (prost_path, attr) in &self.type_attributes {\n            config.type_attribute(prost_path, attr);\n        }\n\n        for prost_path in &self.boxed {\n            config.boxed(prost_path);\n        }\n\n        if let Some(ref paths) = self.btree_map {\n            config.btree_map(paths);\n        }\n\n        if let Some(ref paths) = self.bytes {\n            config.bytes(paths);\n        }\n\n        if self.compile_well_known_types {\n            config.compile_well_known_types();\n        }\n\n        for arg in &self.protoc_args {\n            config.protoc_arg(arg);\n        }\n\n        if let Some(path) = &self.include_file {\n            config.include_file(path);\n        }\n\n        // Note: We don't pass self.disable_comments to prost Config here\n        // because those are meant for service/method paths which are handled\n        // by the ServiceGenerator, not for message paths\n\n        if !self.skip_debug.is_empty() {\n            config.skip_debug(self.skip_debug.clone());\n        }\n\n        if let Some(path) = &self.file_descriptor_set_path {\n            config.file_descriptor_set_path(path);\n        }\n\n        if self.skip_protoc_run {\n            config.skip_protoc_run();\n        }\n\n        if self.build_client || self.build_server {\n            let service_generator = ServiceGenerator::new(\n                self.build_client,\n                self.build_server,\n                self.build_transport,\n                self.client_attributes,\n                self.server_attributes,\n                self.use_arc_self,\n                self.generate_default_stubs,\n                self.proto_path,\n                self.compile_well_known_types,\n                self.codec_path.clone(),\n                self.disable_comments,\n            );\n\n            config.service_generator(Box::new(service_generator));\n        };\n\n        config.compile_fds(fds)?;\n\n        Ok(())\n    }\n\n    /// Turn the builder into a `ServiceGenerator` ready to be passed to `prost-build`s\n    /// `Config::service_generator`.\n    pub fn service_generator(self) -> Box<dyn prost_build::ServiceGenerator> {\n        Box::new(ServiceGenerator::new(\n            self.build_client,\n            self.build_server,\n            self.build_transport,\n            self.client_attributes,\n            self.server_attributes,\n            self.use_arc_self,\n            self.generate_default_stubs,\n            self.proto_path,\n            self.compile_well_known_types,\n            self.codec_path.clone(),\n            self.disable_comments,\n        ))\n    }\n}\n"
  },
  {
    "path": "tonic-prost-build/src/tests.rs",
    "content": "use super::*;\nuse prost_build::{Comments, Method};\nuse quote::quote;\n\nfn create_test_method(input_type: String, output_type: String) -> TonicBuildMethod {\n    TonicBuildMethod {\n        prost_method: Method {\n            name: \"TestMethod\".to_string(),\n            proto_name: \"testMethod\".to_string(),\n            comments: Comments {\n                leading: vec![],\n                trailing: vec![],\n                leading_detached: vec![],\n            },\n            input_type: input_type.clone(),\n            output_type: output_type.clone(),\n            input_proto_type: input_type,\n            output_proto_type: output_type,\n            client_streaming: false,\n            server_streaming: false,\n            options: prost_types::MethodOptions::default(),\n        },\n        codec_path: \"tonic_prost::ProstCodec\".to_string(),\n    }\n}\n\n#[test]\nfn test_request_response_name_google_types_not_compiled() {\n    // Test Google well-known types when compile_well_known_types is false\n    let test_cases = vec![\n        (\".google.protobuf.Empty\", quote!(())),\n        (\".google.protobuf.Any\", quote!(::prost_types::Any)),\n        (\n            \".google.protobuf.StringValue\",\n            quote!(::prost::alloc::string::String),\n        ),\n        (\n            \".google.protobuf.Timestamp\",\n            quote!(::prost_types::Timestamp),\n        ),\n        (\".google.protobuf.Duration\", quote!(::prost_types::Duration)),\n        (\".google.protobuf.Value\", quote!(::prost_types::Value)),\n    ];\n\n    for (type_name, expected) in test_cases {\n        let method = create_test_method(type_name.to_string(), type_name.to_string());\n        let (request, response) = method.request_response_name(\"super\", false);\n\n        assert_eq!(\n            request.to_string(),\n            expected.to_string(),\n            \"Failed for input type: {type_name}\"\n        );\n        assert_eq!(\n            response.to_string(),\n            expected.to_string(),\n            \"Failed for output type: {type_name}\"\n        );\n    }\n}\n\n#[test]\nfn test_request_response_name_google_types_compiled() {\n    // Test Google well-known types when compile_well_known_types is true\n    let test_cases = vec![\n        \".google.protobuf.Empty\",\n        \".google.protobuf.Any\",\n        \".google.protobuf.StringValue\",\n        \".google.protobuf.Timestamp\",\n    ];\n\n    for type_name in test_cases {\n        let method = create_test_method(type_name.to_string(), type_name.to_string());\n        let (request, response) = method.request_response_name(\"super\", true);\n\n        // When compile_well_known_types is true, it should use the normal path logic\n        let expected_path = format!(\n            \"super :: google :: protobuf :: {}\",\n            type_name.trim_start_matches(\".google.protobuf.\")\n        );\n\n        assert_eq!(\n            request.to_string(),\n            expected_path,\n            \"Failed for input type: {type_name}\"\n        );\n        assert_eq!(\n            response.to_string(),\n            expected_path,\n            \"Failed for output type: {type_name}\"\n        );\n    }\n}\n\n#[test]\nfn test_request_response_name_non_path_types() {\n    // Test types in NON_PATH_TYPE_ALLOWLIST\n    let method = create_test_method(\"()\".to_string(), \"()\".to_string());\n    let (request, response) = method.request_response_name(\"super\", false);\n\n    assert_eq!(request.to_string(), \"()\");\n    assert_eq!(response.to_string(), \"()\");\n}\n\n#[test]\nfn test_request_response_name_extern_types() {\n    // Test extern types that start with :: or crate::\n    let test_cases = vec![\n        \"::my_crate::MyType\",\n        \"crate::module::MyType\",\n        \"::external::lib::Type\",\n    ];\n\n    for type_name in test_cases {\n        let method = create_test_method(type_name.to_string(), type_name.to_string());\n        let (request, response) = method.request_response_name(\"super\", false);\n\n        // The parsed TokenStream includes spaces between path segments\n        let expected = match type_name {\n            \"::my_crate::MyType\" => \":: my_crate :: MyType\",\n            \"crate::module::MyType\" => \"crate :: module :: MyType\",\n            \"::external::lib::Type\" => \":: external :: lib :: Type\",\n            _ => panic!(\"Unknown test case: {type_name}\"),\n        };\n\n        assert_eq!(\n            request.to_string(),\n            expected,\n            \"Failed for input type: {type_name}\"\n        );\n        assert_eq!(\n            response.to_string(),\n            expected,\n            \"Failed for output type: {type_name}\"\n        );\n    }\n}\n\n#[test]\nfn test_request_response_name_regular_protobuf_types() {\n    // Test regular protobuf types (with dots)\n    let test_cases = vec![\n        (\"mypackage.MyMessage\", \"super :: mypackage :: MyMessage\"),\n        (\"com.example.User\", \"super :: com :: example :: User\"),\n        (\".mypackage.MyMessage\", \"super :: mypackage :: MyMessage\"), // Leading dot\n        (\n            \"nested.package.Message\",\n            \"super :: nested :: package :: Message\",\n        ),\n    ];\n\n    for (input, expected) in test_cases {\n        let method = create_test_method(input.to_string(), input.to_string());\n        let (request, response) = method.request_response_name(\"super\", false);\n\n        assert_eq!(\n            request.to_string(),\n            expected,\n            \"Failed for input type: {input}\"\n        );\n        assert_eq!(\n            response.to_string(),\n            expected,\n            \"Failed for output type: {input}\"\n        );\n    }\n}\n\n#[test]\nfn test_request_response_name_different_proto_paths() {\n    // Test with different proto_path values\n    let method = create_test_method(\n        \"mypackage.MyMessage\".to_string(),\n        \"mypackage.MyResponse\".to_string(),\n    );\n\n    let test_paths = vec![\"super\", \"crate::proto\", \"crate\"];\n\n    for proto_path in test_paths {\n        let (request, response) = method.request_response_name(proto_path, false);\n\n        // Handle the case where proto_path contains :: which gets spaced out\n        let expected_request = if proto_path.contains(\"::\") {\n            format!(\n                \"{} :: mypackage :: MyMessage\",\n                proto_path.replace(\"::\", \" :: \")\n            )\n        } else {\n            format!(\"{proto_path} :: mypackage :: MyMessage\")\n        };\n        let expected_response = if proto_path.contains(\"::\") {\n            format!(\n                \"{} :: mypackage :: MyResponse\",\n                proto_path.replace(\"::\", \" :: \")\n            )\n        } else {\n            format!(\"{proto_path} :: mypackage :: MyResponse\")\n        };\n\n        assert_eq!(\n            request.to_string(),\n            expected_request,\n            \"Failed for proto_path: {proto_path}\"\n        );\n        assert_eq!(\n            response.to_string(),\n            expected_response,\n            \"Failed for proto_path: {proto_path}\"\n        );\n    }\n}\n\n#[test]\nfn test_request_response_name_mixed_types() {\n    // Test with different request and response types\n    let method = create_test_method(\n        \".google.protobuf.Empty\".to_string(),\n        \"mypackage.MyResponse\".to_string(),\n    );\n    let (request, response) = method.request_response_name(\"super\", false);\n\n    assert_eq!(request.to_string(), \"()\");\n    assert_eq!(response.to_string(), \"super :: mypackage :: MyResponse\");\n\n    // Test with extern type as request and google type as response\n    let method = create_test_method(\n        \"::external::Request\".to_string(),\n        \".google.protobuf.Any\".to_string(),\n    );\n    let (request, response) = method.request_response_name(\"super\", false);\n\n    assert_eq!(request.to_string(), \":: external :: Request\");\n    assert_eq!(response.to_string(), \":: prost_types :: Any\");\n}\n\n#[test]\nfn test_is_google_type() {\n    assert!(is_google_type(\".google.protobuf.Empty\"));\n    assert!(is_google_type(\".google.protobuf.Any\"));\n    assert!(is_google_type(\".google.protobuf.Timestamp\"));\n\n    assert!(!is_google_type(\"google.protobuf.Empty\")); // Missing leading dot\n    assert!(!is_google_type(\".google.api.Http\")); // Not protobuf package\n    assert!(!is_google_type(\"mypackage.Message\"));\n    assert!(!is_google_type(\"\"));\n}\n\n#[test]\nfn test_extended_non_path_type_allowlist() {\n    // prost-build already compiles some well known types into\n    // their rust primitive type counterpart. tonic-prost build must\n    // use the given primitive type.\n    let test_cases = vec![\n        (\"()\", quote!(())),\n        (\"bool\", quote!(bool)),\n        (\"i32\", quote!(i32)),\n        (\"i64\", quote!(i64)),\n        (\"u32\", quote!(u32)),\n        (\"u64\", quote!(u64)),\n        (\"f32\", quote!(f32)),\n        (\"f64\", quote!(f64)),\n    ];\n\n    NON_PATH_TYPE_ALLOWLIST.set(EXTENDED_NON_PATH_TYPE_ALLOWLIST);\n\n    NON_PATH_TYPE_ALLOWLIST.with(|set_allowlist| {\n        let allowlist = set_allowlist.borrow();\n\n        assert_eq!(allowlist.len(), test_cases.len());\n\n        for (type_name, expected) in test_cases {\n            assert!(allowlist.contains(&type_name));\n\n            let method = create_test_method(type_name.to_string(), type_name.to_string());\n            let (request, response) = method.request_response_name(\"super\", false);\n\n            assert_eq!(\n                request.to_string(),\n                expected.to_string(),\n                \"Failed for input type: {type_name}\"\n            );\n            assert_eq!(\n                response.to_string(),\n                expected.to_string(),\n                \"Failed for output type: {type_name}\"\n            );\n        }\n    });\n}\n\n#[test]\nfn test_default_non_path_type_allowlist() {\n    NON_PATH_TYPE_ALLOWLIST.with(|set_allowlist| {\n        let allowlist = set_allowlist.borrow();\n\n        // Verify that the default NON_PATH_TYPE_ALLOWLIST contains expected values.\n        assert!(allowlist.contains(&\"()\"));\n        assert_eq!(allowlist.len(), 1);\n    });\n}\n\n#[test]\nfn test_edge_cases() {\n    // Test empty string types - skip this test as empty strings cause parse errors\n    // This is an edge case that should be handled at a higher level\n\n    // Test types with multiple dots\n    let method = create_test_method(\"a.b.c.d.Message\".to_string(), \"x.y.z.Response\".to_string());\n    let (request, response) = method.request_response_name(\"super\", false);\n    assert_eq!(request.to_string(), \"super :: a :: b :: c :: d :: Message\");\n    assert_eq!(response.to_string(), \"super :: x :: y :: z :: Response\");\n\n    // Test type that ends with () but has a package\n    let method = create_test_method(\"mypackage.()\".to_string(), \"mypackage.()\".to_string());\n    let (request, response) = method.request_response_name(\"super\", false);\n    assert_eq!(request.to_string(), \"mypackage . ()\");\n    assert_eq!(response.to_string(), \"mypackage . ()\");\n}\n"
  },
  {
    "path": "tonic-protobuf/Cargo.toml",
    "content": "[package]\nname = \"tonic-protobuf\"\nversion = \"0.14.0\"\nedition = \"2024\"\nauthors = [\"gRPC Authors\"]\nlicense = \"MIT\"\npublish = false\nrust-version = { workspace = true }\n\n[dependencies]\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false, features = [\"codegen\"] }\nbytes = \"1\"\nprotobuf = { version = \"4.33.0-release\" }\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n    \"tonic::*\",\n    \"protobuf::codegen_traits::Message\",\n]\n"
  },
  {
    "path": "tonic-protobuf/src/lib.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse bytes::{Buf, BufMut};\nuse std::marker::PhantomData;\nuse tonic::{\n    Status,\n    codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder},\n};\n\npub use protobuf;\nuse protobuf::Message;\n\n/// A [`Codec`] that implements `application/grpc+proto` via the protobuf\n/// library.\n#[derive(Debug, Clone)]\npub struct ProtoCodec<T, U> {\n    _pd: PhantomData<(T, U)>,\n}\n\nimpl<T, U> Default for ProtoCodec<T, U> {\n    fn default() -> Self {\n        Self { _pd: PhantomData }\n    }\n}\n\nimpl<T, U> Codec for ProtoCodec<T, U>\nwhere\n    T: Message + Send + 'static,\n    U: Message + Default + Send + 'static,\n{\n    type Encode = T;\n    type Decode = U;\n\n    type Encoder = ProtoEncoder<T>;\n    type Decoder = ProtoDecoder<U>;\n\n    fn encoder(&mut self) -> Self::Encoder {\n        ProtoEncoder { _pd: PhantomData }\n    }\n\n    fn decoder(&mut self) -> Self::Decoder {\n        ProtoDecoder { _pd: PhantomData }\n    }\n}\n\n/// A [`Encoder`] that knows how to encode `T`.\n#[derive(Debug, Clone, Default)]\npub struct ProtoEncoder<T> {\n    _pd: PhantomData<T>,\n}\n\nimpl<T> ProtoEncoder<T> {\n    /// Get a new encoder with explicit buffer settings\n    pub fn new() -> Self {\n        Self { _pd: PhantomData }\n    }\n}\n\nimpl<T: Message> Encoder for ProtoEncoder<T> {\n    type Item = T;\n    type Error = Status;\n\n    fn encode(&mut self, item: Self::Item, buf: &mut EncodeBuf<'_>) -> Result<(), Self::Error> {\n        // The protobuf library doesn't support serializing into a user-provided\n        // buffer. Instead, it allocates its own buffer, resulting in an extra\n        // copy and allocation.\n        // TODO: #2345 - Find a way to avoid this extra copy.\n        let serialized = item.serialize().map_err(from_decode_error)?;\n        buf.put_slice(serialized.as_slice());\n        Ok(())\n    }\n}\n\n/// A [`Decoder`] that knows how to decode `U`.\n#[derive(Debug, Clone, Default)]\npub struct ProtoDecoder<U> {\n    _pd: PhantomData<U>,\n}\n\nimpl<U> ProtoDecoder<U> {\n    /// Get a new decoder.\n    pub fn new() -> Self {\n        Self { _pd: PhantomData }\n    }\n}\n\nimpl<U: Message + Default> Decoder for ProtoDecoder<U> {\n    type Item = U;\n    type Error = Status;\n\n    fn decode(&mut self, buf: &mut DecodeBuf<'_>) -> Result<Option<Self::Item>, Self::Error> {\n        let slice = buf.chunk();\n        let item = U::parse(slice).map_err(from_decode_error)?;\n        buf.advance(slice.len());\n        Ok(Some(item))\n    }\n}\n\nfn from_decode_error(error: impl std::error::Error) -> tonic::Status {\n    // Map Protobuf parse errors to an INTERNAL status code, as per\n    // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md\n    Status::internal(error.to_string())\n}\n"
  },
  {
    "path": "tonic-protobuf-build/Cargo.toml",
    "content": "[package]\nname = \"tonic-protobuf-build\"\nversion = \"0.14.0\"\nedition = \"2024\"\nauthors = [\"gRPC Authors\"]\nlicense = \"MIT\"\npublish = false\nrust-version = { workspace = true }\n\n[dependencies]\nprettyplease = \"0.2.35\"\nprotobuf-codegen = { version = \"4.33.0-release\" }\nsyn = \"2.0.104\"\n\n[build-dependencies]\ncmake = \"0.1\"\n"
  },
  {
    "path": "tonic-protobuf-build/README.md",
    "content": "# tonic-protobuf-build\n\nCompiles proto files via protobuf rust and generates service stubs and proto\ndefinitions for use with tonic.\n\n## Features\n\nRequired dependencies\n\n```toml\n[dependencies]\ntonic = \"<tonic-version>\"\nprotobuf = \"<protobuf-version>\"\ntonic-protobuf =  \"<tonic-version>\"\n\n[build-dependencies]\ntonic-protobuf-build = \"<tonic-version>\"\n```\n\nYou must ensure you have the following programs in your PATH:\n1. protoc\n1. protoc-gen-rust-grpc\n\n## Getting Started\n\n`tonic-protobuf-build` works by being included as a [`build.rs` file](https://doc.rust-lang.org/cargo/reference/build-scripts.html) at the root of the binary/library.\n\nYou can rely on the defaults via\n\n```rust,no_run\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    tonic_protobuf_build::CodeGen::new()\n        .include(\"proto\")\n        .inputs([\"service.proto\"])\n        .compile()?;\n    Ok(())\n}\n```\n\nOr configure the generated code deeper via\n\n```rust,no_run\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let dependency = tonic_protobuf_build::Dependency::builder()\n        .crate_name(\"external_protos\".to_string())\n        .proto_import_paths(vec![PathBuf::from(\"external/message.proto\")])\n        .proto_files(vec![\"message.proto\".to_string()])\n        .build()?;\n\n    tonic_protobuf_build::CodeGen::new()\n        .generate_message_code(false)\n        .inputs([\"proto/helloworld/helloworld.proto\"])\n        .include(\"external\")\n        .message_module_path(\"super::proto\")\n        .dependencies(vec![dependency])\n        //.out_dir(\"src/generated\")  // you can change the generated code's location\n        .compile()?;\n   Ok(())\n}\n```\n\nThen you can reference the generated Rust like this in your code:\n```rust,ignore\nmod protos {\n    // Include message code.\n    include!(concat!(env!(\"OUT_DIR\"), \"proto/helloworld/generated.rs\"));\n}\n\nmod grpc {\n    // Include service code.\n    include!(concat!(env!(\"OUT_DIR\"), \"proto/helloworld/helloworld_grpc.pb.rs\"));\n}\n```\n\nIf you don't modify the `message_module_path`, you can use the `include_proto`\nmacro to simplify the import code.\n```rust,ignore\npub mod grpc_pb {\n    grpc::include_proto!(\"proto/helloworld\", \"helloworld\");\n}\n```\n\nOr if you want to save the generated code in your own code base,\nyou can uncomment the line `.output_dir(...)` above, and in your lib file\nconfig a mod like this:\n```rust,ignore\npub mod generated {\n    pub mod helloworld {\n        pub mod proto {\n            include!(\"helloworld/generated.rs\");\n        }\n\n        pub mod grpc {\n            include!(\"helloworld/test_grpc.pb.rs\");\n        }\n    }\n}\n```\n"
  },
  {
    "path": "tonic-protobuf-build/build.rs",
    "content": "fn main() {\n    cmake::build(\"../protoc-gen-rust-grpc\");\n\n    println!(\"cargo:rerun-if-changed=../protoc-gen-rust-grpc/cmake\");\n    println!(\"cargo:rerun-if-changed=../protoc-gen-rust-grpc/CMakeLists.txt\");\n}\n"
  },
  {
    "path": "tonic-protobuf-build/src/lib.rs",
    "content": "/*\n *\n * Copyright 2025 gRPC authors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n *\n */\n\nuse std::fs::{self, read_to_string};\nuse std::io::Write;\nuse std::path::{Path, PathBuf};\n\nuse syn::parse_file;\n\npub fn protoc() -> String {\n    format!(\"{}/bin/protoc\", env!(\"OUT_DIR\"))\n}\n\npub fn protoc_gen_rust_grpc() -> String {\n    format!(\"{}/bin/protoc-gen-rust-grpc\", env!(\"OUT_DIR\"))\n}\n\npub fn bin() -> String {\n    format!(\"{}/bin\", env!(\"OUT_DIR\"))\n}\n\n/// Details about a crate containing proto files with symbols referenced in\n/// the file being compiled currently.\n#[derive(Debug, Clone)]\npub struct Dependency {\n    crate_name: String,\n    proto_import_paths: Vec<PathBuf>,\n    proto_files: Vec<String>,\n}\n\nimpl Dependency {\n    pub fn builder() -> DependencyBuilder {\n        DependencyBuilder::default()\n    }\n}\n\n#[derive(Default, Debug)]\npub struct DependencyBuilder {\n    crate_name: Option<String>,\n    proto_import_paths: Vec<PathBuf>,\n    proto_files: Vec<String>,\n}\n\nimpl DependencyBuilder {\n    /// Name of the external crate.\n    pub fn crate_name(mut self, name: impl Into<String>) -> Self {\n        self.crate_name = Some(name.into());\n        self\n    }\n\n    /// List of paths .proto files whose codegen is present in the crate. This\n    /// is used to re-run the build command if required.\n    pub fn proto_import_path(mut self, path: impl Into<PathBuf>) -> Self {\n        self.proto_import_paths.push(path.into());\n        self\n    }\n\n    /// List of .proto file names whose codegen is present in the crate.\n    pub fn proto_import_paths(mut self, paths: Vec<PathBuf>) -> Self {\n        self.proto_import_paths = paths;\n        self\n    }\n\n    pub fn proto_file(mut self, file: impl Into<String>) -> Self {\n        self.proto_files.push(file.into());\n        self\n    }\n\n    pub fn proto_files(mut self, files: Vec<String>) -> Self {\n        self.proto_files = files;\n        self\n    }\n\n    pub fn build(self) -> Result<Dependency, &'static str> {\n        let crate_name = self.crate_name.ok_or(\"crate_name is required\")?;\n        Ok(Dependency {\n            crate_name,\n            proto_import_paths: self.proto_import_paths,\n            proto_files: self.proto_files,\n        })\n    }\n}\n\nimpl From<&Dependency> for protobuf_codegen::Dependency {\n    fn from(val: &Dependency) -> Self {\n        protobuf_codegen::Dependency {\n            crate_name: val.crate_name.clone(),\n            proto_import_paths: val.proto_import_paths.clone(),\n            proto_files: val.proto_files.clone(),\n        }\n    }\n}\n\n/// Service generator builder.\n#[derive(Debug, Clone)]\npub struct CodeGen {\n    inputs: Vec<PathBuf>,\n    output_dir: PathBuf,\n    includes: Vec<PathBuf>,\n    dependencies: Vec<Dependency>,\n    message_module_path: Option<String>,\n    // Whether to generate message code, defaults to true.\n    generate_message_code: bool,\n    should_format_code: bool,\n}\n\nimpl CodeGen {\n    pub fn new() -> Self {\n        Self {\n            inputs: Vec::new(),\n            output_dir: PathBuf::from(std::env::var(\"OUT_DIR\").unwrap()),\n            includes: Vec::new(),\n            dependencies: Vec::new(),\n            message_module_path: None,\n            generate_message_code: true,\n            should_format_code: true,\n        }\n    }\n\n    /// Sets whether to generate the message code. This can be disabled if the\n    /// message code is being generated independently.\n    pub fn generate_message_code(&mut self, enable: bool) -> &mut Self {\n        self.generate_message_code = enable;\n        self\n    }\n\n    /// Adds a proto file to compile.\n    pub fn input(&mut self, input: impl AsRef<Path>) -> &mut Self {\n        self.inputs.push(input.as_ref().to_owned());\n        self\n    }\n\n    /// Adds a proto file to compile.\n    pub fn inputs(&mut self, inputs: impl IntoIterator<Item = impl AsRef<Path>>) -> &mut Self {\n        self.inputs\n            .extend(inputs.into_iter().map(|input| input.as_ref().to_owned()));\n        self\n    }\n\n    /// Enables or disables formatting of generated code.\n    pub fn should_format_code(&mut self, enable: bool) -> &mut Self {\n        self.should_format_code = enable;\n        self\n    }\n\n    /// Sets the directory for the files generated by protoc. The generated code\n    /// will be present in a subdirectory corresponding to the path of the\n    /// proto file withing the included directories.\n    pub fn output_dir(&mut self, output_dir: impl AsRef<Path>) -> &mut Self {\n        self.output_dir = output_dir.as_ref().to_owned();\n        self\n    }\n\n    /// Add a directory for protoc to scan for .proto files.\n    pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self {\n        self.includes.push(include.as_ref().to_owned());\n        self\n    }\n\n    /// Add a directory for protoc to scan for .proto files.\n    pub fn includes(&mut self, includes: impl Iterator<Item = impl AsRef<Path>>) -> &mut Self {\n        self.includes.extend(\n            includes\n                .into_iter()\n                .map(|include| include.as_ref().to_owned()),\n        );\n        self\n    }\n\n    /// Adds a list of Rust crates along with the proto files whose generated\n    /// messages they contains.\n    pub fn dependencies(&mut self, deps: Vec<Dependency>) -> &mut Self {\n        self.dependencies.extend(deps);\n        self\n    }\n\n    /// Sets path of the module containing the generated message code. This is\n    /// \"self\" by default, i.e. the service code expects the message structs to\n    /// be present in the same module. Set this if the message and service\n    /// codegen needs to live in separate modules.\n    pub fn message_module_path(&mut self, message_path: &str) -> &mut Self {\n        self.message_module_path = Some(message_path.to_string());\n        self\n    }\n\n    pub fn compile(&self) -> Result<(), String> {\n        // Generate the message code.\n        if self.generate_message_code {\n            protobuf_codegen::CodeGen::new()\n                .inputs(self.inputs.clone())\n                .output_dir(self.output_dir.clone())\n                .includes(self.includes.iter())\n                .dependency(self.dependencies.iter().map(|d| d.into()).collect())\n                .generate_and_compile()\n                .unwrap();\n        }\n        let crate_mapping_path = if self.generate_message_code {\n            self.output_dir.join(\"crate_mapping.txt\")\n        } else {\n            self.generate_crate_mapping_file()\n        };\n\n        // Generate the service code.\n        let mut cmd = std::process::Command::new(\"protoc\");\n        for input in &self.inputs {\n            cmd.arg(input);\n        }\n        if !self.output_dir.exists() {\n            // Attempt to make the directory if it doesn't exist\n            let _ = std::fs::create_dir(&self.output_dir);\n        }\n\n        if !self.generate_message_code {\n            for include in &self.includes {\n                println!(\"cargo:rerun-if-changed={}\", include.display());\n            }\n            for dep in &self.dependencies {\n                for path in &dep.proto_import_paths {\n                    println!(\"cargo:rerun-if-changed={}\", path.display());\n                }\n            }\n        }\n\n        cmd.arg(format!(\"--rust-grpc_out={}\", self.output_dir.display()));\n        cmd.arg(format!(\n            \"--rust-grpc_opt=crate_mapping={}\",\n            crate_mapping_path.display()\n        ));\n        if let Some(message_path) = &self.message_module_path {\n            cmd.arg(format!(\n                \"--rust-grpc_opt=message_module_path={message_path}\",\n            ));\n        }\n\n        for include in &self.includes {\n            cmd.arg(format!(\"--proto_path={}\", include.display()));\n        }\n        for dep in &self.dependencies {\n            for path in &dep.proto_import_paths {\n                cmd.arg(format!(\"--proto_path={}\", path.display()));\n            }\n        }\n\n        let output = cmd\n            .output()\n            .map_err(|e| format!(\"failed to run protoc: {e}\"))?;\n        println!(\"{}\", std::str::from_utf8(&output.stdout).unwrap());\n        eprintln!(\"{}\", std::str::from_utf8(&output.stderr).unwrap());\n        assert!(output.status.success());\n\n        if self.should_format_code {\n            self.format_code();\n        }\n        Ok(())\n    }\n\n    fn format_code(&self) {\n        let mut generated_file_paths = Vec::new();\n        let output_dir = &self.output_dir;\n        if self.generate_message_code {\n            generated_file_paths.push(output_dir.join(\"generated.rs\"));\n        }\n        for proto_path in &self.inputs {\n            let Some(stem) = proto_path.file_stem().and_then(|s| s.to_str()) else {\n                continue;\n            };\n            generated_file_paths.push(output_dir.join(format!(\"{stem}_grpc.pb.rs\")));\n            if self.generate_message_code {\n                generated_file_paths.push(output_dir.join(format!(\"{stem}.u.pb.rs\")));\n            }\n        }\n\n        for path in &generated_file_paths {\n            // The path may not exist if there are no services present in the\n            // proto file.\n            if path.exists() {\n                let src = read_to_string(path).expect(\"Failed to read generated file\");\n                let syntax = parse_file(&src).unwrap();\n                let formatted = prettyplease::unparse(&syntax);\n                fs::write(path, formatted).unwrap();\n            }\n        }\n    }\n\n    fn generate_crate_mapping_file(&self) -> PathBuf {\n        let crate_mapping_path = self.output_dir.join(\"crate_mapping.txt\");\n        let mut file = fs::File::create(crate_mapping_path.clone()).unwrap();\n        for dep in &self.dependencies {\n            file.write_all(format!(\"{}\\n\", dep.crate_name).as_bytes())\n                .unwrap();\n            file.write_all(format!(\"{}\\n\", dep.proto_files.len()).as_bytes())\n                .unwrap();\n            for f in &dep.proto_files {\n                file.write_all(format!(\"{f}\\n\").as_bytes()).unwrap();\n            }\n        }\n        crate_mapping_path\n    }\n}\n\nimpl Default for CodeGen {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "tonic-reflection/Cargo.toml",
    "content": "[package]\nauthors = [\n  \"James Nugent <james@jen20.com>\",\n  \"Samani G. Gikandi <samani@gojulas.com>\",\n]\ncategories = [\"network-programming\", \"asynchronous\"]\ndescription = \"\"\"\nServer Reflection module of `tonic` gRPC implementation.\n\"\"\"\nedition = \"2024\"\nhomepage = \"https://github.com/hyperium/tonic\"\nkeywords = [\"rpc\", \"grpc\", \"async\", \"reflection\"]\nlicense = \"MIT\"\nname = \"tonic-reflection\"\nreadme = \"README.md\"\nrepository = \"https://github.com/hyperium/tonic\"\nversion = \"0.14.5\"\nrust-version = { workspace = true }\n\n[package.metadata.docs.rs]\nall-features = true\n\n[features]\nserver = [\"dep:prost-types\", \"dep:tokio\", \"dep:tokio-stream\"]\ndefault = [\"server\"]\n\n[dependencies]\nprost = \"0.14\"\nprost-types = {version = \"0.14\", optional = true}\ntokio = { version = \"1.0\", features = [\"sync\", \"rt\"], optional = true }\ntokio-stream = {version = \"0.1\", default-features = false, optional = true }\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false, features = [\"codegen\"] }\ntonic-prost = { version = \"0.14.0\", path = \"../tonic-prost\", default-features = false }\n\n[dev-dependencies]\ntokio-stream = {version = \"0.1\", default-features = false, features = [\"net\"]}\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false, features = [\"transport\"] }\n\n[lints]\nworkspace = true\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  \"tonic::*\",\n\n  # major released\n  \"bytes::*\",\n  \"http::*\",\n  \"http_body::*\",\n\n  # not major released\n  \"prost::*\",\n  \"prost_types::*\",\n\n  \"futures_core::stream::Stream\",\n  \"tower_service::Service\",\n]\n"
  },
  {
    "path": "tonic-reflection/README.md",
    "content": "# tonic-reflection\n\nA `tonic` based gRPC reflection implementation.\n"
  },
  {
    "path": "tonic-reflection/proto/reflection_v1.proto",
    "content": "// Copyright 2016 The gRPC Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Service exported by server reflection.  A more complete description of how\n// server reflection works can be found at\n// https://github.com/grpc/grpc/blob/master/doc/server-reflection.md\n//\n// The canonical version of this proto can be found at\n// https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto\n\nsyntax = \"proto3\";\n\npackage grpc.reflection.v1;\n\noption go_package = \"google.golang.org/grpc/reflection/grpc_reflection_v1\";\noption java_multiple_files = true;\noption java_package = \"io.grpc.reflection.v1\";\noption java_outer_classname = \"ServerReflectionProto\";\n\nservice ServerReflection {\n  // The reflection service is structured as a bidirectional stream, ensuring\n  // all related requests go to a single server.\n  rpc ServerReflectionInfo(stream ServerReflectionRequest)\n      returns (stream ServerReflectionResponse);\n}\n\n// The message sent by the client when calling ServerReflectionInfo method.\nmessage ServerReflectionRequest {\n  string host = 1;\n  // To use reflection service, the client should set one of the following\n  // fields in message_request. The server distinguishes requests by their\n  // defined field and then handles them using corresponding methods.\n  oneof message_request {\n    // Find a proto file by the file name.\n    string file_by_filename = 3;\n\n    // Find the proto file that declares the given fully-qualified symbol name.\n    // This field should be a fully-qualified symbol name\n    // (e.g. <package>.<service>[.<method>] or <package>.<type>).\n    string file_containing_symbol = 4;\n\n    // Find the proto file which defines an extension extending the given\n    // message type with the given field number.\n    ExtensionRequest file_containing_extension = 5;\n\n    // Finds the tag numbers used by all known extensions of the given message\n    // type, and appends them to ExtensionNumberResponse in an undefined order.\n    // Its corresponding method is best-effort: it's not guaranteed that the\n    // reflection service will implement this method, and it's not guaranteed\n    // that this method will provide all extensions. Returns\n    // StatusCode::UNIMPLEMENTED if it's not implemented.\n    // This field should be a fully-qualified type name. The format is\n    // <package>.<type>\n    string all_extension_numbers_of_type = 6;\n\n    // List the full names of registered services. The content will not be\n    // checked.\n    string list_services = 7;\n  }\n}\n\n// The type name and extension number sent by the client when requesting\n// file_containing_extension.\nmessage ExtensionRequest {\n  // Fully-qualified type name. The format should be <package>.<type>\n  string containing_type = 1;\n  int32 extension_number = 2;\n}\n\n// The message sent by the server to answer ServerReflectionInfo method.\nmessage ServerReflectionResponse {\n  string valid_host = 1;\n  ServerReflectionRequest original_request = 2;\n  // The server sets one of the following fields according to the message_request\n  // in the request.\n  oneof message_response {\n    // This message is used to answer file_by_filename, file_containing_symbol,\n    // file_containing_extension requests with transitive dependencies.\n    // As the repeated label is not allowed in oneof fields, we use a\n    // FileDescriptorResponse message to encapsulate the repeated fields.\n    // The reflection service is allowed to avoid sending FileDescriptorProtos\n    // that were previously sent in response to earlier requests in the stream.\n    FileDescriptorResponse file_descriptor_response = 4;\n\n    // This message is used to answer all_extension_numbers_of_type requests.\n    ExtensionNumberResponse all_extension_numbers_response = 5;\n\n    // This message is used to answer list_services requests.\n    ListServiceResponse list_services_response = 6;\n\n    // This message is used when an error occurs.\n    ErrorResponse error_response = 7;\n  }\n}\n\n// Serialized FileDescriptorProto messages sent by the server answering\n// a file_by_filename, file_containing_symbol, or file_containing_extension\n// request.\nmessage FileDescriptorResponse {\n  // Serialized FileDescriptorProto messages. We avoid taking a dependency on\n  // descriptor.proto, which uses proto2 only features, by making them opaque\n  // bytes instead.\n  repeated bytes file_descriptor_proto = 1;\n}\n\n// A list of extension numbers sent by the server answering\n// all_extension_numbers_of_type request.\nmessage ExtensionNumberResponse {\n  // Full name of the base type, including the package name. The format\n  // is <package>.<type>\n  string base_type_name = 1;\n  repeated int32 extension_number = 2;\n}\n\n// A list of ServiceResponse sent by the server answering list_services request.\nmessage ListServiceResponse {\n  // The information of each service may be expanded in the future, so we use\n  // ServiceResponse message to encapsulate it.\n  repeated ServiceResponse service = 1;\n}\n\n// The information of a single service used by ListServiceResponse to answer\n// list_services request.\nmessage ServiceResponse {\n  // Full name of a registered service, including its package name. The format\n  // is <package>.<service>\n  string name = 1;\n}\n\n// The error code and error message sent by the server when an error occurs.\nmessage ErrorResponse {\n  // This field uses the error codes defined in grpc::StatusCode.\n  int32 error_code = 1;\n  string error_message = 2;\n}\n\n"
  },
  {
    "path": "tonic-reflection/proto/reflection_v1alpha.proto",
    "content": "// Copyright 2016 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Service exported by server reflection\n\nsyntax = \"proto3\";\n\npackage grpc.reflection.v1alpha;\n\nservice ServerReflection {\n    // The reflection service is structured as a bidirectional stream, ensuring\n    // all related requests go to a single server.\n    rpc ServerReflectionInfo(stream ServerReflectionRequest)\n    returns (stream ServerReflectionResponse);\n}\n\n// The message sent by the client when calling ServerReflectionInfo method.\nmessage ServerReflectionRequest {\n    string host = 1;\n    // To use reflection service, the client should set one of the following\n    // fields in message_request. The server distinguishes requests by their\n    // defined field and then handles them using corresponding methods.\n    oneof message_request {\n        // Find a proto file by the file name.\n        string file_by_filename = 3;\n\n        // Find the proto file that declares the given fully-qualified symbol name.\n        // This field should be a fully-qualified symbol name\n        // (e.g. <package>.<service>[.<method>] or <package>.<type>).\n        string file_containing_symbol = 4;\n\n        // Find the proto file which defines an extension extending the given\n        // message type with the given field number.\n        ExtensionRequest file_containing_extension = 5;\n\n        // Finds the tag numbers used by all known extensions of extendee_type, and\n        // appends them to ExtensionNumberResponse in an undefined order.\n        // Its corresponding method is best-effort: it's not guaranteed that the\n        // reflection service will implement this method, and it's not guaranteed\n        // that this method will provide all extensions. Returns\n        // StatusCode::UNIMPLEMENTED if it's not implemented.\n        // This field should be a fully-qualified type name. The format is\n        // <package>.<type>\n        string all_extension_numbers_of_type = 6;\n\n        // List the full names of registered services. The content will not be\n        // checked.\n        string list_services = 7;\n    }\n}\n\n// The type name and extension number sent by the client when requesting\n// file_containing_extension.\nmessage ExtensionRequest {\n    // Fully-qualified type name. The format should be <package>.<type>\n    string containing_type = 1;\n    int32 extension_number = 2;\n}\n\n// The message sent by the server to answer ServerReflectionInfo method.\nmessage ServerReflectionResponse {\n    string valid_host = 1;\n    ServerReflectionRequest original_request = 2;\n    // The server sets one of the following fields according to the\n    // message_request in the request.\n    oneof message_response {\n        // This message is used to answer file_by_filename, file_containing_symbol,\n        // file_containing_extension requests with transitive dependencies.\n        // As the repeated label is not allowed in oneof fields, we use a\n        // FileDescriptorResponse message to encapsulate the repeated fields.\n        // The reflection service is allowed to avoid sending FileDescriptorProtos\n        // that were previously sent in response to earlier requests in the stream.\n        FileDescriptorResponse file_descriptor_response = 4;\n\n        // This message is used to answer all_extension_numbers_of_type requests.\n        ExtensionNumberResponse all_extension_numbers_response = 5;\n\n        // This message is used to answer list_services requests.\n        ListServiceResponse list_services_response = 6;\n\n        // This message is used when an error occurs.\n        ErrorResponse error_response = 7;\n    }\n}\n\n// Serialized FileDescriptorProto messages sent by the server answering\n// a file_by_filename, file_containing_symbol, or file_containing_extension\n// request.\nmessage FileDescriptorResponse {\n    // Serialized FileDescriptorProto messages. We avoid taking a dependency on\n    // descriptor.proto, which uses proto2 only features, by making them opaque\n    // bytes instead.\n    repeated bytes file_descriptor_proto = 1;\n}\n\n// A list of extension numbers sent by the server answering\n// all_extension_numbers_of_type request.\nmessage ExtensionNumberResponse {\n    // Full name of the base type, including the package name. The format\n    // is <package>.<type>\n    string base_type_name = 1;\n    repeated int32 extension_number = 2;\n}\n\n// A list of ServiceResponse sent by the server answering list_services request.\nmessage ListServiceResponse {\n    // The information of each service may be expanded in the future, so we use\n    // ServiceResponse message to encapsulate it.\n    repeated ServiceResponse service = 1;\n}\n\n// The information of a single service used by ListServiceResponse to answer\n// list_services request.\nmessage ServiceResponse {\n    // Full name of a registered service, including its package name. The format\n    // is <package>.<service>\n    string name = 1;\n}\n\n// The error code and error message sent by the server when an error occurs.\nmessage ErrorResponse {\n    // This field uses the error codes defined in grpc::StatusCode.\n    int32 error_code = 1;\n    string error_message = 2;\n}\n"
  },
  {
    "path": "tonic-reflection/src/generated/grpc_reflection_v1.rs",
    "content": "// This file is @generated by prost-build.\n/// The message sent by the client when calling ServerReflectionInfo method.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ServerReflectionRequest {\n    #[prost(string, tag = \"1\")]\n    pub host: ::prost::alloc::string::String,\n    /// To use reflection service, the client should set one of the following\n    /// fields in message_request. The server distinguishes requests by their\n    /// defined field and then handles them using corresponding methods.\n    #[prost(oneof = \"server_reflection_request::MessageRequest\", tags = \"3, 4, 5, 6, 7\")]\n    pub message_request: ::core::option::Option<\n        server_reflection_request::MessageRequest,\n    >,\n}\n/// Nested message and enum types in `ServerReflectionRequest`.\npub mod server_reflection_request {\n    /// To use reflection service, the client should set one of the following\n    /// fields in message_request. The server distinguishes requests by their\n    /// defined field and then handles them using corresponding methods.\n    #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)]\n    pub enum MessageRequest {\n        /// Find a proto file by the file name.\n        #[prost(string, tag = \"3\")]\n        FileByFilename(::prost::alloc::string::String),\n        /// Find the proto file that declares the given fully-qualified symbol name.\n        /// This field should be a fully-qualified symbol name\n        /// (e.g. <package>.<service>\\[.<method>\\] or <package>.<type>).\n        #[prost(string, tag = \"4\")]\n        FileContainingSymbol(::prost::alloc::string::String),\n        /// Find the proto file which defines an extension extending the given\n        /// message type with the given field number.\n        #[prost(message, tag = \"5\")]\n        FileContainingExtension(super::ExtensionRequest),\n        /// Finds the tag numbers used by all known extensions of the given message\n        /// type, and appends them to ExtensionNumberResponse in an undefined order.\n        /// Its corresponding method is best-effort: it's not guaranteed that the\n        /// reflection service will implement this method, and it's not guaranteed\n        /// that this method will provide all extensions. Returns\n        /// StatusCode::UNIMPLEMENTED if it's not implemented.\n        /// This field should be a fully-qualified type name. The format is\n        /// <package>.<type>\n        #[prost(string, tag = \"6\")]\n        AllExtensionNumbersOfType(::prost::alloc::string::String),\n        /// List the full names of registered services. The content will not be\n        /// checked.\n        #[prost(string, tag = \"7\")]\n        ListServices(::prost::alloc::string::String),\n    }\n}\n/// The type name and extension number sent by the client when requesting\n/// file_containing_extension.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ExtensionRequest {\n    /// Fully-qualified type name. The format should be <package>.<type>\n    #[prost(string, tag = \"1\")]\n    pub containing_type: ::prost::alloc::string::String,\n    #[prost(int32, tag = \"2\")]\n    pub extension_number: i32,\n}\n/// The message sent by the server to answer ServerReflectionInfo method.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct ServerReflectionResponse {\n    #[prost(string, tag = \"1\")]\n    pub valid_host: ::prost::alloc::string::String,\n    #[prost(message, optional, tag = \"2\")]\n    pub original_request: ::core::option::Option<ServerReflectionRequest>,\n    /// The server sets one of the following fields according to the message_request\n    /// in the request.\n    #[prost(oneof = \"server_reflection_response::MessageResponse\", tags = \"4, 5, 6, 7\")]\n    pub message_response: ::core::option::Option<\n        server_reflection_response::MessageResponse,\n    >,\n}\n/// Nested message and enum types in `ServerReflectionResponse`.\npub mod server_reflection_response {\n    /// The server sets one of the following fields according to the message_request\n    /// in the request.\n    #[derive(Clone, PartialEq, ::prost::Oneof)]\n    pub enum MessageResponse {\n        /// This message is used to answer file_by_filename, file_containing_symbol,\n        /// file_containing_extension requests with transitive dependencies.\n        /// As the repeated label is not allowed in oneof fields, we use a\n        /// FileDescriptorResponse message to encapsulate the repeated fields.\n        /// The reflection service is allowed to avoid sending FileDescriptorProtos\n        /// that were previously sent in response to earlier requests in the stream.\n        #[prost(message, tag = \"4\")]\n        FileDescriptorResponse(super::FileDescriptorResponse),\n        /// This message is used to answer all_extension_numbers_of_type requests.\n        #[prost(message, tag = \"5\")]\n        AllExtensionNumbersResponse(super::ExtensionNumberResponse),\n        /// This message is used to answer list_services requests.\n        #[prost(message, tag = \"6\")]\n        ListServicesResponse(super::ListServiceResponse),\n        /// This message is used when an error occurs.\n        #[prost(message, tag = \"7\")]\n        ErrorResponse(super::ErrorResponse),\n    }\n}\n/// Serialized FileDescriptorProto messages sent by the server answering\n/// a file_by_filename, file_containing_symbol, or file_containing_extension\n/// request.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct FileDescriptorResponse {\n    /// Serialized FileDescriptorProto messages. We avoid taking a dependency on\n    /// descriptor.proto, which uses proto2 only features, by making them opaque\n    /// bytes instead.\n    #[prost(bytes = \"vec\", repeated, tag = \"1\")]\n    pub file_descriptor_proto: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,\n}\n/// A list of extension numbers sent by the server answering\n/// all_extension_numbers_of_type request.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ExtensionNumberResponse {\n    /// Full name of the base type, including the package name. The format\n    /// is <package>.<type>\n    #[prost(string, tag = \"1\")]\n    pub base_type_name: ::prost::alloc::string::String,\n    #[prost(int32, repeated, tag = \"2\")]\n    pub extension_number: ::prost::alloc::vec::Vec<i32>,\n}\n/// A list of ServiceResponse sent by the server answering list_services request.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct ListServiceResponse {\n    /// The information of each service may be expanded in the future, so we use\n    /// ServiceResponse message to encapsulate it.\n    #[prost(message, repeated, tag = \"1\")]\n    pub service: ::prost::alloc::vec::Vec<ServiceResponse>,\n}\n/// The information of a single service used by ListServiceResponse to answer\n/// list_services request.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ServiceResponse {\n    /// Full name of a registered service, including its package name. The format\n    /// is <package>.<service>\n    #[prost(string, tag = \"1\")]\n    pub name: ::prost::alloc::string::String,\n}\n/// The error code and error message sent by the server when an error occurs.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ErrorResponse {\n    /// This field uses the error codes defined in grpc::StatusCode.\n    #[prost(int32, tag = \"1\")]\n    pub error_code: i32,\n    #[prost(string, tag = \"2\")]\n    pub error_message: ::prost::alloc::string::String,\n}\n/// Generated client implementations.\npub mod server_reflection_client {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    use tonic::codegen::http::Uri;\n    #[derive(Debug, Clone)]\n    pub struct ServerReflectionClient<T> {\n        inner: tonic::client::Grpc<T>,\n    }\n    impl<T> ServerReflectionClient<T>\n    where\n        T: tonic::client::GrpcService<tonic::body::Body>,\n        T::Error: Into<StdError>,\n        T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,\n        <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,\n    {\n        pub fn new(inner: T) -> Self {\n            let inner = tonic::client::Grpc::new(inner);\n            Self { inner }\n        }\n        pub fn with_origin(inner: T, origin: Uri) -> Self {\n            let inner = tonic::client::Grpc::with_origin(inner, origin);\n            Self { inner }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> ServerReflectionClient<InterceptedService<T, F>>\n        where\n            F: tonic::service::Interceptor,\n            T::ResponseBody: Default,\n            T: tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n                Response = http::Response<\n                    <T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody,\n                >,\n            >,\n            <T as tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n            >>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,\n        {\n            ServerReflectionClient::new(InterceptedService::new(inner, interceptor))\n        }\n        /// Compress requests with the given encoding.\n        ///\n        /// This requires the server to support it otherwise it might respond with an\n        /// error.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.send_compressed(encoding);\n            self\n        }\n        /// Enable decompressing responses.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.accept_compressed(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_decoding_message_size(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_encoding_message_size(limit);\n            self\n        }\n        /// The reflection service is structured as a bidirectional stream, ensuring\n        /// all related requests go to a single server.\n        pub async fn server_reflection_info(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<\n                Message = super::ServerReflectionRequest,\n            >,\n        ) -> std::result::Result<\n            tonic::Response<tonic::codec::Streaming<super::ServerReflectionResponse>>,\n            tonic::Status,\n        > {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.reflection.v1.ServerReflection/ServerReflectionInfo\",\n            );\n            let mut req = request.into_streaming_request();\n            req.extensions_mut()\n                .insert(\n                    GrpcMethod::new(\n                        \"grpc.reflection.v1.ServerReflection\",\n                        \"ServerReflectionInfo\",\n                    ),\n                );\n            self.inner.streaming(req, path, codec).await\n        }\n    }\n}\n/// Generated server implementations.\npub mod server_reflection_server {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    /// Generated trait containing gRPC methods that should be implemented for use with ServerReflectionServer.\n    #[async_trait]\n    pub trait ServerReflection: std::marker::Send + std::marker::Sync + 'static {\n        /// Server streaming response type for the ServerReflectionInfo method.\n        type ServerReflectionInfoStream: tonic::codegen::tokio_stream::Stream<\n                Item = std::result::Result<\n                    super::ServerReflectionResponse,\n                    tonic::Status,\n                >,\n            >\n            + std::marker::Send\n            + 'static;\n        /// The reflection service is structured as a bidirectional stream, ensuring\n        /// all related requests go to a single server.\n        async fn server_reflection_info(\n            &self,\n            request: tonic::Request<tonic::Streaming<super::ServerReflectionRequest>>,\n        ) -> std::result::Result<\n            tonic::Response<Self::ServerReflectionInfoStream>,\n            tonic::Status,\n        >;\n    }\n    #[derive(Debug)]\n    pub struct ServerReflectionServer<T> {\n        inner: Arc<T>,\n        accept_compression_encodings: EnabledCompressionEncodings,\n        send_compression_encodings: EnabledCompressionEncodings,\n        max_decoding_message_size: Option<usize>,\n        max_encoding_message_size: Option<usize>,\n    }\n    impl<T> ServerReflectionServer<T> {\n        pub fn new(inner: T) -> Self {\n            Self::from_arc(Arc::new(inner))\n        }\n        pub fn from_arc(inner: Arc<T>) -> Self {\n            Self {\n                inner,\n                accept_compression_encodings: Default::default(),\n                send_compression_encodings: Default::default(),\n                max_decoding_message_size: None,\n                max_encoding_message_size: None,\n            }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> InterceptedService<Self, F>\n        where\n            F: tonic::service::Interceptor,\n        {\n            InterceptedService::new(Self::new(inner), interceptor)\n        }\n        /// Enable decompressing requests with the given encoding.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.accept_compression_encodings.enable(encoding);\n            self\n        }\n        /// Compress responses with the given encoding, if the client supports it.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.send_compression_encodings.enable(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.max_decoding_message_size = Some(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.max_encoding_message_size = Some(limit);\n            self\n        }\n    }\n    impl<T, B> tonic::codegen::Service<http::Request<B>> for ServerReflectionServer<T>\n    where\n        T: ServerReflection,\n        B: Body + std::marker::Send + 'static,\n        B::Error: Into<StdError> + std::marker::Send + 'static,\n    {\n        type Response = http::Response<tonic::body::Body>;\n        type Error = std::convert::Infallible;\n        type Future = BoxFuture<Self::Response, Self::Error>;\n        fn poll_ready(\n            &mut self,\n            _cx: &mut Context<'_>,\n        ) -> Poll<std::result::Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n        fn call(&mut self, req: http::Request<B>) -> Self::Future {\n            match req.uri().path() {\n                \"/grpc.reflection.v1.ServerReflection/ServerReflectionInfo\" => {\n                    #[allow(non_camel_case_types)]\n                    struct ServerReflectionInfoSvc<T: ServerReflection>(pub Arc<T>);\n                    impl<\n                        T: ServerReflection,\n                    > tonic::server::StreamingService<super::ServerReflectionRequest>\n                    for ServerReflectionInfoSvc<T> {\n                        type Response = super::ServerReflectionResponse;\n                        type ResponseStream = T::ServerReflectionInfoStream;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::ResponseStream>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<\n                                tonic::Streaming<super::ServerReflectionRequest>,\n                            >,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as ServerReflection>::server_reflection_info(\n                                        &inner,\n                                        request,\n                                    )\n                                    .await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = ServerReflectionInfoSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.streaming(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                _ => {\n                    Box::pin(async move {\n                        let mut response = http::Response::new(\n                            tonic::body::Body::default(),\n                        );\n                        let headers = response.headers_mut();\n                        headers\n                            .insert(\n                                tonic::Status::GRPC_STATUS,\n                                (tonic::Code::Unimplemented as i32).into(),\n                            );\n                        headers\n                            .insert(\n                                http::header::CONTENT_TYPE,\n                                tonic::metadata::GRPC_CONTENT_TYPE,\n                            );\n                        Ok(response)\n                    })\n                }\n            }\n        }\n    }\n    impl<T> Clone for ServerReflectionServer<T> {\n        fn clone(&self) -> Self {\n            let inner = self.inner.clone();\n            Self {\n                inner,\n                accept_compression_encodings: self.accept_compression_encodings,\n                send_compression_encodings: self.send_compression_encodings,\n                max_decoding_message_size: self.max_decoding_message_size,\n                max_encoding_message_size: self.max_encoding_message_size,\n            }\n        }\n    }\n    /// Generated gRPC service name\n    pub const SERVICE_NAME: &str = \"grpc.reflection.v1.ServerReflection\";\n    impl<T> tonic::server::NamedService for ServerReflectionServer<T> {\n        const NAME: &'static str = SERVICE_NAME;\n    }\n}\n"
  },
  {
    "path": "tonic-reflection/src/generated/grpc_reflection_v1alpha.rs",
    "content": "// This file is @generated by prost-build.\n/// The message sent by the client when calling ServerReflectionInfo method.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ServerReflectionRequest {\n    #[prost(string, tag = \"1\")]\n    pub host: ::prost::alloc::string::String,\n    /// To use reflection service, the client should set one of the following\n    /// fields in message_request. The server distinguishes requests by their\n    /// defined field and then handles them using corresponding methods.\n    #[prost(oneof = \"server_reflection_request::MessageRequest\", tags = \"3, 4, 5, 6, 7\")]\n    pub message_request: ::core::option::Option<\n        server_reflection_request::MessageRequest,\n    >,\n}\n/// Nested message and enum types in `ServerReflectionRequest`.\npub mod server_reflection_request {\n    /// To use reflection service, the client should set one of the following\n    /// fields in message_request. The server distinguishes requests by their\n    /// defined field and then handles them using corresponding methods.\n    #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)]\n    pub enum MessageRequest {\n        /// Find a proto file by the file name.\n        #[prost(string, tag = \"3\")]\n        FileByFilename(::prost::alloc::string::String),\n        /// Find the proto file that declares the given fully-qualified symbol name.\n        /// This field should be a fully-qualified symbol name\n        /// (e.g. <package>.<service>\\[.<method>\\] or <package>.<type>).\n        #[prost(string, tag = \"4\")]\n        FileContainingSymbol(::prost::alloc::string::String),\n        /// Find the proto file which defines an extension extending the given\n        /// message type with the given field number.\n        #[prost(message, tag = \"5\")]\n        FileContainingExtension(super::ExtensionRequest),\n        /// Finds the tag numbers used by all known extensions of extendee_type, and\n        /// appends them to ExtensionNumberResponse in an undefined order.\n        /// Its corresponding method is best-effort: it's not guaranteed that the\n        /// reflection service will implement this method, and it's not guaranteed\n        /// that this method will provide all extensions. Returns\n        /// StatusCode::UNIMPLEMENTED if it's not implemented.\n        /// This field should be a fully-qualified type name. The format is\n        /// <package>.<type>\n        #[prost(string, tag = \"6\")]\n        AllExtensionNumbersOfType(::prost::alloc::string::String),\n        /// List the full names of registered services. The content will not be\n        /// checked.\n        #[prost(string, tag = \"7\")]\n        ListServices(::prost::alloc::string::String),\n    }\n}\n/// The type name and extension number sent by the client when requesting\n/// file_containing_extension.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ExtensionRequest {\n    /// Fully-qualified type name. The format should be <package>.<type>\n    #[prost(string, tag = \"1\")]\n    pub containing_type: ::prost::alloc::string::String,\n    #[prost(int32, tag = \"2\")]\n    pub extension_number: i32,\n}\n/// The message sent by the server to answer ServerReflectionInfo method.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct ServerReflectionResponse {\n    #[prost(string, tag = \"1\")]\n    pub valid_host: ::prost::alloc::string::String,\n    #[prost(message, optional, tag = \"2\")]\n    pub original_request: ::core::option::Option<ServerReflectionRequest>,\n    /// The server sets one of the following fields according to the\n    /// message_request in the request.\n    #[prost(oneof = \"server_reflection_response::MessageResponse\", tags = \"4, 5, 6, 7\")]\n    pub message_response: ::core::option::Option<\n        server_reflection_response::MessageResponse,\n    >,\n}\n/// Nested message and enum types in `ServerReflectionResponse`.\npub mod server_reflection_response {\n    /// The server sets one of the following fields according to the\n    /// message_request in the request.\n    #[derive(Clone, PartialEq, ::prost::Oneof)]\n    pub enum MessageResponse {\n        /// This message is used to answer file_by_filename, file_containing_symbol,\n        /// file_containing_extension requests with transitive dependencies.\n        /// As the repeated label is not allowed in oneof fields, we use a\n        /// FileDescriptorResponse message to encapsulate the repeated fields.\n        /// The reflection service is allowed to avoid sending FileDescriptorProtos\n        /// that were previously sent in response to earlier requests in the stream.\n        #[prost(message, tag = \"4\")]\n        FileDescriptorResponse(super::FileDescriptorResponse),\n        /// This message is used to answer all_extension_numbers_of_type requests.\n        #[prost(message, tag = \"5\")]\n        AllExtensionNumbersResponse(super::ExtensionNumberResponse),\n        /// This message is used to answer list_services requests.\n        #[prost(message, tag = \"6\")]\n        ListServicesResponse(super::ListServiceResponse),\n        /// This message is used when an error occurs.\n        #[prost(message, tag = \"7\")]\n        ErrorResponse(super::ErrorResponse),\n    }\n}\n/// Serialized FileDescriptorProto messages sent by the server answering\n/// a file_by_filename, file_containing_symbol, or file_containing_extension\n/// request.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct FileDescriptorResponse {\n    /// Serialized FileDescriptorProto messages. We avoid taking a dependency on\n    /// descriptor.proto, which uses proto2 only features, by making them opaque\n    /// bytes instead.\n    #[prost(bytes = \"vec\", repeated, tag = \"1\")]\n    pub file_descriptor_proto: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,\n}\n/// A list of extension numbers sent by the server answering\n/// all_extension_numbers_of_type request.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ExtensionNumberResponse {\n    /// Full name of the base type, including the package name. The format\n    /// is <package>.<type>\n    #[prost(string, tag = \"1\")]\n    pub base_type_name: ::prost::alloc::string::String,\n    #[prost(int32, repeated, tag = \"2\")]\n    pub extension_number: ::prost::alloc::vec::Vec<i32>,\n}\n/// A list of ServiceResponse sent by the server answering list_services request.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct ListServiceResponse {\n    /// The information of each service may be expanded in the future, so we use\n    /// ServiceResponse message to encapsulate it.\n    #[prost(message, repeated, tag = \"1\")]\n    pub service: ::prost::alloc::vec::Vec<ServiceResponse>,\n}\n/// The information of a single service used by ListServiceResponse to answer\n/// list_services request.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ServiceResponse {\n    /// Full name of a registered service, including its package name. The format\n    /// is <package>.<service>\n    #[prost(string, tag = \"1\")]\n    pub name: ::prost::alloc::string::String,\n}\n/// The error code and error message sent by the server when an error occurs.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ErrorResponse {\n    /// This field uses the error codes defined in grpc::StatusCode.\n    #[prost(int32, tag = \"1\")]\n    pub error_code: i32,\n    #[prost(string, tag = \"2\")]\n    pub error_message: ::prost::alloc::string::String,\n}\n/// Generated client implementations.\npub mod server_reflection_client {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    use tonic::codegen::http::Uri;\n    #[derive(Debug, Clone)]\n    pub struct ServerReflectionClient<T> {\n        inner: tonic::client::Grpc<T>,\n    }\n    impl<T> ServerReflectionClient<T>\n    where\n        T: tonic::client::GrpcService<tonic::body::Body>,\n        T::Error: Into<StdError>,\n        T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,\n        <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,\n    {\n        pub fn new(inner: T) -> Self {\n            let inner = tonic::client::Grpc::new(inner);\n            Self { inner }\n        }\n        pub fn with_origin(inner: T, origin: Uri) -> Self {\n            let inner = tonic::client::Grpc::with_origin(inner, origin);\n            Self { inner }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> ServerReflectionClient<InterceptedService<T, F>>\n        where\n            F: tonic::service::Interceptor,\n            T::ResponseBody: Default,\n            T: tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n                Response = http::Response<\n                    <T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody,\n                >,\n            >,\n            <T as tonic::codegen::Service<\n                http::Request<tonic::body::Body>,\n            >>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,\n        {\n            ServerReflectionClient::new(InterceptedService::new(inner, interceptor))\n        }\n        /// Compress requests with the given encoding.\n        ///\n        /// This requires the server to support it otherwise it might respond with an\n        /// error.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.send_compressed(encoding);\n            self\n        }\n        /// Enable decompressing responses.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.accept_compressed(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_decoding_message_size(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_encoding_message_size(limit);\n            self\n        }\n        /// The reflection service is structured as a bidirectional stream, ensuring\n        /// all related requests go to a single server.\n        pub async fn server_reflection_info(\n            &mut self,\n            request: impl tonic::IntoStreamingRequest<\n                Message = super::ServerReflectionRequest,\n            >,\n        ) -> std::result::Result<\n            tonic::Response<tonic::codec::Streaming<super::ServerReflectionResponse>>,\n            tonic::Status,\n        > {\n            self.inner\n                .ready()\n                .await\n                .map_err(|e| {\n                    tonic::Status::unknown(\n                        format!(\"Service was not ready: {}\", e.into()),\n                    )\n                })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\n                \"/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo\",\n            );\n            let mut req = request.into_streaming_request();\n            req.extensions_mut()\n                .insert(\n                    GrpcMethod::new(\n                        \"grpc.reflection.v1alpha.ServerReflection\",\n                        \"ServerReflectionInfo\",\n                    ),\n                );\n            self.inner.streaming(req, path, codec).await\n        }\n    }\n}\n/// Generated server implementations.\npub mod server_reflection_server {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value,\n    )]\n    use tonic::codegen::*;\n    /// Generated trait containing gRPC methods that should be implemented for use with ServerReflectionServer.\n    #[async_trait]\n    pub trait ServerReflection: std::marker::Send + std::marker::Sync + 'static {\n        /// Server streaming response type for the ServerReflectionInfo method.\n        type ServerReflectionInfoStream: tonic::codegen::tokio_stream::Stream<\n                Item = std::result::Result<\n                    super::ServerReflectionResponse,\n                    tonic::Status,\n                >,\n            >\n            + std::marker::Send\n            + 'static;\n        /// The reflection service is structured as a bidirectional stream, ensuring\n        /// all related requests go to a single server.\n        async fn server_reflection_info(\n            &self,\n            request: tonic::Request<tonic::Streaming<super::ServerReflectionRequest>>,\n        ) -> std::result::Result<\n            tonic::Response<Self::ServerReflectionInfoStream>,\n            tonic::Status,\n        >;\n    }\n    #[derive(Debug)]\n    pub struct ServerReflectionServer<T> {\n        inner: Arc<T>,\n        accept_compression_encodings: EnabledCompressionEncodings,\n        send_compression_encodings: EnabledCompressionEncodings,\n        max_decoding_message_size: Option<usize>,\n        max_encoding_message_size: Option<usize>,\n    }\n    impl<T> ServerReflectionServer<T> {\n        pub fn new(inner: T) -> Self {\n            Self::from_arc(Arc::new(inner))\n        }\n        pub fn from_arc(inner: Arc<T>) -> Self {\n            Self {\n                inner,\n                accept_compression_encodings: Default::default(),\n                send_compression_encodings: Default::default(),\n                max_decoding_message_size: None,\n                max_encoding_message_size: None,\n            }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> InterceptedService<Self, F>\n        where\n            F: tonic::service::Interceptor,\n        {\n            InterceptedService::new(Self::new(inner), interceptor)\n        }\n        /// Enable decompressing requests with the given encoding.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.accept_compression_encodings.enable(encoding);\n            self\n        }\n        /// Compress responses with the given encoding, if the client supports it.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.send_compression_encodings.enable(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.max_decoding_message_size = Some(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.max_encoding_message_size = Some(limit);\n            self\n        }\n    }\n    impl<T, B> tonic::codegen::Service<http::Request<B>> for ServerReflectionServer<T>\n    where\n        T: ServerReflection,\n        B: Body + std::marker::Send + 'static,\n        B::Error: Into<StdError> + std::marker::Send + 'static,\n    {\n        type Response = http::Response<tonic::body::Body>;\n        type Error = std::convert::Infallible;\n        type Future = BoxFuture<Self::Response, Self::Error>;\n        fn poll_ready(\n            &mut self,\n            _cx: &mut Context<'_>,\n        ) -> Poll<std::result::Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n        fn call(&mut self, req: http::Request<B>) -> Self::Future {\n            match req.uri().path() {\n                \"/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo\" => {\n                    #[allow(non_camel_case_types)]\n                    struct ServerReflectionInfoSvc<T: ServerReflection>(pub Arc<T>);\n                    impl<\n                        T: ServerReflection,\n                    > tonic::server::StreamingService<super::ServerReflectionRequest>\n                    for ServerReflectionInfoSvc<T> {\n                        type Response = super::ServerReflectionResponse;\n                        type ResponseStream = T::ServerReflectionInfoStream;\n                        type Future = BoxFuture<\n                            tonic::Response<Self::ResponseStream>,\n                            tonic::Status,\n                        >;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<\n                                tonic::Streaming<super::ServerReflectionRequest>,\n                            >,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut = async move {\n                                <T as ServerReflection>::server_reflection_info(\n                                        &inner,\n                                        request,\n                                    )\n                                    .await\n                            };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = ServerReflectionInfoSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.streaming(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                _ => {\n                    Box::pin(async move {\n                        let mut response = http::Response::new(\n                            tonic::body::Body::default(),\n                        );\n                        let headers = response.headers_mut();\n                        headers\n                            .insert(\n                                tonic::Status::GRPC_STATUS,\n                                (tonic::Code::Unimplemented as i32).into(),\n                            );\n                        headers\n                            .insert(\n                                http::header::CONTENT_TYPE,\n                                tonic::metadata::GRPC_CONTENT_TYPE,\n                            );\n                        Ok(response)\n                    })\n                }\n            }\n        }\n    }\n    impl<T> Clone for ServerReflectionServer<T> {\n        fn clone(&self) -> Self {\n            let inner = self.inner.clone();\n            Self {\n                inner,\n                accept_compression_encodings: self.accept_compression_encodings,\n                send_compression_encodings: self.send_compression_encodings,\n                max_decoding_message_size: self.max_decoding_message_size,\n                max_encoding_message_size: self.max_encoding_message_size,\n            }\n        }\n    }\n    /// Generated gRPC service name\n    pub const SERVICE_NAME: &str = \"grpc.reflection.v1alpha.ServerReflection\";\n    impl<T> tonic::server::NamedService for ServerReflectionServer<T> {\n        const NAME: &'static str = SERVICE_NAME;\n    }\n}\n"
  },
  {
    "path": "tonic-reflection/src/generated/reflection_v1_fds.rs",
    "content": "// This file is @generated by codegen.\n//  Copyright 2016 The gRPC Authors\n// \n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n// \n//      http://www.apache.org/licenses/LICENSE-2.0\n// \n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//  Service exported by server reflection.  A more complete description of how\n//  server reflection works can be found at\n//  https://github.com/grpc/grpc/blob/master/doc/server-reflection.md\n// \n//  The canonical version of this proto can be found at\n//  https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto\n// \n/// Byte encoded FILE_DESCRIPTOR_SET.\npub const FILE_DESCRIPTOR_SET: &[u8] = &[\n    10u8, 192u8, 13u8, 10u8, 19u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 95u8, 118u8, 49u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 18u8, 18u8,\n    103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8,\n    105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 34u8, 243u8, 2u8, 10u8, 23u8, 83u8, 101u8,\n    114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 18u8, 18u8, 10u8, 4u8,\n    104u8, 111u8, 115u8, 116u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 4u8, 104u8, 111u8,\n    115u8, 116u8, 18u8, 42u8, 10u8, 16u8, 102u8, 105u8, 108u8, 101u8, 95u8, 98u8, 121u8,\n    95u8, 102u8, 105u8, 108u8, 101u8, 110u8, 97u8, 109u8, 101u8, 24u8, 3u8, 32u8, 1u8,\n    40u8, 9u8, 72u8, 0u8, 82u8, 14u8, 102u8, 105u8, 108u8, 101u8, 66u8, 121u8, 70u8,\n    105u8, 108u8, 101u8, 110u8, 97u8, 109u8, 101u8, 18u8, 54u8, 10u8, 22u8, 102u8, 105u8,\n    108u8, 101u8, 95u8, 99u8, 111u8, 110u8, 116u8, 97u8, 105u8, 110u8, 105u8, 110u8,\n    103u8, 95u8, 115u8, 121u8, 109u8, 98u8, 111u8, 108u8, 24u8, 4u8, 32u8, 1u8, 40u8,\n    9u8, 72u8, 0u8, 82u8, 20u8, 102u8, 105u8, 108u8, 101u8, 67u8, 111u8, 110u8, 116u8,\n    97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 83u8, 121u8, 109u8, 98u8, 111u8, 108u8,\n    18u8, 98u8, 10u8, 25u8, 102u8, 105u8, 108u8, 101u8, 95u8, 99u8, 111u8, 110u8, 116u8,\n    97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 95u8, 101u8, 120u8, 116u8, 101u8, 110u8,\n    115u8, 105u8, 111u8, 110u8, 24u8, 5u8, 32u8, 1u8, 40u8, 11u8, 50u8, 36u8, 46u8,\n    103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8,\n    105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 46u8, 69u8, 120u8, 116u8, 101u8, 110u8,\n    115u8, 105u8, 111u8, 110u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 72u8,\n    0u8, 82u8, 23u8, 102u8, 105u8, 108u8, 101u8, 67u8, 111u8, 110u8, 116u8, 97u8, 105u8,\n    110u8, 105u8, 110u8, 103u8, 69u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8,\n    110u8, 18u8, 66u8, 10u8, 29u8, 97u8, 108u8, 108u8, 95u8, 101u8, 120u8, 116u8, 101u8,\n    110u8, 115u8, 105u8, 111u8, 110u8, 95u8, 110u8, 117u8, 109u8, 98u8, 101u8, 114u8,\n    115u8, 95u8, 111u8, 102u8, 95u8, 116u8, 121u8, 112u8, 101u8, 24u8, 6u8, 32u8, 1u8,\n    40u8, 9u8, 72u8, 0u8, 82u8, 25u8, 97u8, 108u8, 108u8, 69u8, 120u8, 116u8, 101u8,\n    110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 115u8,\n    79u8, 102u8, 84u8, 121u8, 112u8, 101u8, 18u8, 37u8, 10u8, 13u8, 108u8, 105u8, 115u8,\n    116u8, 95u8, 115u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 115u8, 24u8, 7u8, 32u8,\n    1u8, 40u8, 9u8, 72u8, 0u8, 82u8, 12u8, 108u8, 105u8, 115u8, 116u8, 83u8, 101u8,\n    114u8, 118u8, 105u8, 99u8, 101u8, 115u8, 66u8, 17u8, 10u8, 15u8, 109u8, 101u8, 115u8,\n    115u8, 97u8, 103u8, 101u8, 95u8, 114u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8,\n    34u8, 102u8, 10u8, 16u8, 69u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8,\n    110u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 18u8, 39u8, 10u8, 15u8, 99u8,\n    111u8, 110u8, 116u8, 97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 95u8, 116u8, 121u8,\n    112u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 14u8, 99u8, 111u8, 110u8, 116u8,\n    97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 84u8, 121u8, 112u8, 101u8, 18u8, 41u8, 10u8,\n    16u8, 101u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 95u8, 110u8,\n    117u8, 109u8, 98u8, 101u8, 114u8, 24u8, 2u8, 32u8, 1u8, 40u8, 5u8, 82u8, 15u8, 101u8,\n    120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8,\n    101u8, 114u8, 34u8, 174u8, 4u8, 10u8, 24u8, 83u8, 101u8, 114u8, 118u8, 101u8, 114u8,\n    82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 82u8, 101u8,\n    115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 29u8, 10u8, 10u8, 118u8, 97u8, 108u8,\n    105u8, 100u8, 95u8, 104u8, 111u8, 115u8, 116u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8,\n    82u8, 9u8, 118u8, 97u8, 108u8, 105u8, 100u8, 72u8, 111u8, 115u8, 116u8, 18u8, 86u8,\n    10u8, 16u8, 111u8, 114u8, 105u8, 103u8, 105u8, 110u8, 97u8, 108u8, 95u8, 114u8,\n    101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 24u8, 2u8, 32u8, 1u8, 40u8, 11u8, 50u8,\n    43u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8,\n    116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 46u8, 83u8, 101u8, 114u8, 118u8,\n    101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8,\n    82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 82u8, 15u8, 111u8, 114u8, 105u8,\n    103u8, 105u8, 110u8, 97u8, 108u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8,\n    18u8, 102u8, 10u8, 24u8, 102u8, 105u8, 108u8, 101u8, 95u8, 100u8, 101u8, 115u8, 99u8,\n    114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 95u8, 114u8, 101u8, 115u8, 112u8, 111u8,\n    110u8, 115u8, 101u8, 24u8, 4u8, 32u8, 1u8, 40u8, 11u8, 50u8, 42u8, 46u8, 103u8,\n    114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 46u8, 118u8, 49u8, 46u8, 70u8, 105u8, 108u8, 101u8, 68u8, 101u8, 115u8,\n    99u8, 114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8,\n    110u8, 115u8, 101u8, 72u8, 0u8, 82u8, 22u8, 102u8, 105u8, 108u8, 101u8, 68u8, 101u8,\n    115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 18u8, 114u8, 10u8, 30u8, 97u8, 108u8, 108u8, 95u8, 101u8,\n    120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 95u8, 110u8, 117u8, 109u8,\n    98u8, 101u8, 114u8, 115u8, 95u8, 114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8,\n    101u8, 24u8, 5u8, 32u8, 1u8, 40u8, 11u8, 50u8, 43u8, 46u8, 103u8, 114u8, 112u8, 99u8,\n    46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8,\n    118u8, 49u8, 46u8, 69u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8,\n    78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8,\n    115u8, 101u8, 72u8, 0u8, 82u8, 27u8, 97u8, 108u8, 108u8, 69u8, 120u8, 116u8, 101u8,\n    110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 115u8,\n    82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 95u8, 10u8, 22u8, 108u8,\n    105u8, 115u8, 116u8, 95u8, 115u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 115u8,\n    95u8, 114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 24u8, 6u8, 32u8, 1u8,\n    40u8, 11u8, 50u8, 39u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8,\n    108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 46u8, 76u8, 105u8,\n    115u8, 116u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 82u8, 101u8, 115u8,\n    112u8, 111u8, 110u8, 115u8, 101u8, 72u8, 0u8, 82u8, 20u8, 108u8, 105u8, 115u8, 116u8,\n    83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 115u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 18u8, 74u8, 10u8, 14u8, 101u8, 114u8, 114u8, 111u8,\n    114u8, 95u8, 114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 24u8, 7u8, 32u8,\n    1u8, 40u8, 11u8, 50u8, 33u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8,\n    102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 46u8, 69u8,\n    114u8, 114u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8,\n    72u8, 0u8, 82u8, 13u8, 101u8, 114u8, 114u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 66u8, 18u8, 10u8, 16u8, 109u8, 101u8, 115u8, 115u8, 97u8,\n    103u8, 101u8, 95u8, 114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 34u8,\n    76u8, 10u8, 22u8, 70u8, 105u8, 108u8, 101u8, 68u8, 101u8, 115u8, 99u8, 114u8, 105u8,\n    112u8, 116u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8,\n    18u8, 50u8, 10u8, 21u8, 102u8, 105u8, 108u8, 101u8, 95u8, 100u8, 101u8, 115u8, 99u8,\n    114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 95u8, 112u8, 114u8, 111u8, 116u8, 111u8,\n    24u8, 1u8, 32u8, 3u8, 40u8, 12u8, 82u8, 19u8, 102u8, 105u8, 108u8, 101u8, 68u8,\n    101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 80u8, 114u8, 111u8,\n    116u8, 111u8, 34u8, 106u8, 10u8, 23u8, 69u8, 120u8, 116u8, 101u8, 110u8, 115u8,\n    105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 82u8, 101u8, 115u8,\n    112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 36u8, 10u8, 14u8, 98u8, 97u8, 115u8, 101u8,\n    95u8, 116u8, 121u8, 112u8, 101u8, 95u8, 110u8, 97u8, 109u8, 101u8, 24u8, 1u8, 32u8,\n    1u8, 40u8, 9u8, 82u8, 12u8, 98u8, 97u8, 115u8, 101u8, 84u8, 121u8, 112u8, 101u8,\n    78u8, 97u8, 109u8, 101u8, 18u8, 41u8, 10u8, 16u8, 101u8, 120u8, 116u8, 101u8, 110u8,\n    115u8, 105u8, 111u8, 110u8, 95u8, 110u8, 117u8, 109u8, 98u8, 101u8, 114u8, 24u8, 2u8,\n    32u8, 3u8, 40u8, 5u8, 82u8, 15u8, 101u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8,\n    111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 34u8, 84u8, 10u8, 19u8, 76u8,\n    105u8, 115u8, 116u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 82u8, 101u8,\n    115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 61u8, 10u8, 7u8, 115u8, 101u8, 114u8,\n    118u8, 105u8, 99u8, 101u8, 24u8, 1u8, 32u8, 3u8, 40u8, 11u8, 50u8, 35u8, 46u8, 103u8,\n    114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 46u8, 118u8, 49u8, 46u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8,\n    82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 82u8, 7u8, 115u8, 101u8,\n    114u8, 118u8, 105u8, 99u8, 101u8, 34u8, 37u8, 10u8, 15u8, 83u8, 101u8, 114u8, 118u8,\n    105u8, 99u8, 101u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8,\n    18u8, 10u8, 4u8, 110u8, 97u8, 109u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8,\n    4u8, 110u8, 97u8, 109u8, 101u8, 34u8, 83u8, 10u8, 13u8, 69u8, 114u8, 114u8, 111u8,\n    114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 29u8, 10u8, 10u8,\n    101u8, 114u8, 114u8, 111u8, 114u8, 95u8, 99u8, 111u8, 100u8, 101u8, 24u8, 1u8, 32u8,\n    1u8, 40u8, 5u8, 82u8, 9u8, 101u8, 114u8, 114u8, 111u8, 114u8, 67u8, 111u8, 100u8,\n    101u8, 18u8, 35u8, 10u8, 13u8, 101u8, 114u8, 114u8, 111u8, 114u8, 95u8, 109u8, 101u8,\n    115u8, 115u8, 97u8, 103u8, 101u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 12u8, 101u8,\n    114u8, 114u8, 111u8, 114u8, 77u8, 101u8, 115u8, 115u8, 97u8, 103u8, 101u8, 50u8,\n    137u8, 1u8, 10u8, 16u8, 83u8, 101u8, 114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8,\n    108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 18u8, 117u8, 10u8, 20u8, 83u8, 101u8,\n    114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 73u8, 110u8, 102u8, 111u8, 18u8, 43u8, 46u8, 103u8, 114u8, 112u8, 99u8,\n    46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8,\n    118u8, 49u8, 46u8, 83u8, 101u8, 114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8,\n    108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 82u8, 101u8, 113u8, 117u8, 101u8,\n    115u8, 116u8, 26u8, 44u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8,\n    108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 46u8, 83u8, 101u8,\n    114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 40u8, 1u8, 48u8,\n    1u8, 66u8, 102u8, 10u8, 21u8, 105u8, 111u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8,\n    114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8,\n    49u8, 66u8, 21u8, 83u8, 101u8, 114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8, 108u8,\n    101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 80u8, 114u8, 111u8, 116u8, 111u8, 80u8, 1u8,\n    90u8, 52u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 103u8, 111u8, 108u8,\n    97u8, 110u8, 103u8, 46u8, 111u8, 114u8, 103u8, 47u8, 103u8, 114u8, 112u8, 99u8, 47u8,\n    114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 47u8, 103u8,\n    114u8, 112u8, 99u8, 95u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 95u8, 118u8, 49u8, 98u8, 6u8, 112u8, 114u8, 111u8, 116u8, 111u8, 51u8,\n];\n"
  },
  {
    "path": "tonic-reflection/src/generated/reflection_v1alpha1_fds.rs",
    "content": "// This file is @generated by codegen.\n//  Copyright 2016 gRPC authors.\n// \n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n// \n//      http://www.apache.org/licenses/LICENSE-2.0\n// \n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//  Service exported by server reflection\n// \n/// Byte encoded FILE_DESCRIPTOR_SET.\npub const FILE_DESCRIPTOR_SET: &[u8] = &[\n    10u8, 143u8, 13u8, 10u8, 24u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8,\n    111u8, 110u8, 95u8, 118u8, 49u8, 97u8, 108u8, 112u8, 104u8, 97u8, 46u8, 112u8, 114u8,\n    111u8, 116u8, 111u8, 18u8, 23u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8,\n    102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 97u8,\n    108u8, 112u8, 104u8, 97u8, 34u8, 248u8, 2u8, 10u8, 23u8, 83u8, 101u8, 114u8, 118u8,\n    101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8,\n    82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 18u8, 18u8, 10u8, 4u8, 104u8, 111u8,\n    115u8, 116u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 4u8, 104u8, 111u8, 115u8, 116u8,\n    18u8, 42u8, 10u8, 16u8, 102u8, 105u8, 108u8, 101u8, 95u8, 98u8, 121u8, 95u8, 102u8,\n    105u8, 108u8, 101u8, 110u8, 97u8, 109u8, 101u8, 24u8, 3u8, 32u8, 1u8, 40u8, 9u8,\n    72u8, 0u8, 82u8, 14u8, 102u8, 105u8, 108u8, 101u8, 66u8, 121u8, 70u8, 105u8, 108u8,\n    101u8, 110u8, 97u8, 109u8, 101u8, 18u8, 54u8, 10u8, 22u8, 102u8, 105u8, 108u8, 101u8,\n    95u8, 99u8, 111u8, 110u8, 116u8, 97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 95u8,\n    115u8, 121u8, 109u8, 98u8, 111u8, 108u8, 24u8, 4u8, 32u8, 1u8, 40u8, 9u8, 72u8, 0u8,\n    82u8, 20u8, 102u8, 105u8, 108u8, 101u8, 67u8, 111u8, 110u8, 116u8, 97u8, 105u8,\n    110u8, 105u8, 110u8, 103u8, 83u8, 121u8, 109u8, 98u8, 111u8, 108u8, 18u8, 103u8,\n    10u8, 25u8, 102u8, 105u8, 108u8, 101u8, 95u8, 99u8, 111u8, 110u8, 116u8, 97u8, 105u8,\n    110u8, 105u8, 110u8, 103u8, 95u8, 101u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8,\n    111u8, 110u8, 24u8, 5u8, 32u8, 1u8, 40u8, 11u8, 50u8, 41u8, 46u8, 103u8, 114u8,\n    112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8,\n    110u8, 46u8, 118u8, 49u8, 97u8, 108u8, 112u8, 104u8, 97u8, 46u8, 69u8, 120u8, 116u8,\n    101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8,\n    116u8, 72u8, 0u8, 82u8, 23u8, 102u8, 105u8, 108u8, 101u8, 67u8, 111u8, 110u8, 116u8,\n    97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 69u8, 120u8, 116u8, 101u8, 110u8, 115u8,\n    105u8, 111u8, 110u8, 18u8, 66u8, 10u8, 29u8, 97u8, 108u8, 108u8, 95u8, 101u8, 120u8,\n    116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 95u8, 110u8, 117u8, 109u8, 98u8,\n    101u8, 114u8, 115u8, 95u8, 111u8, 102u8, 95u8, 116u8, 121u8, 112u8, 101u8, 24u8, 6u8,\n    32u8, 1u8, 40u8, 9u8, 72u8, 0u8, 82u8, 25u8, 97u8, 108u8, 108u8, 69u8, 120u8, 116u8,\n    101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8,\n    115u8, 79u8, 102u8, 84u8, 121u8, 112u8, 101u8, 18u8, 37u8, 10u8, 13u8, 108u8, 105u8,\n    115u8, 116u8, 95u8, 115u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 115u8, 24u8, 7u8,\n    32u8, 1u8, 40u8, 9u8, 72u8, 0u8, 82u8, 12u8, 108u8, 105u8, 115u8, 116u8, 83u8, 101u8,\n    114u8, 118u8, 105u8, 99u8, 101u8, 115u8, 66u8, 17u8, 10u8, 15u8, 109u8, 101u8, 115u8,\n    115u8, 97u8, 103u8, 101u8, 95u8, 114u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8,\n    34u8, 102u8, 10u8, 16u8, 69u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8,\n    110u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 18u8, 39u8, 10u8, 15u8, 99u8,\n    111u8, 110u8, 116u8, 97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 95u8, 116u8, 121u8,\n    112u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 14u8, 99u8, 111u8, 110u8, 116u8,\n    97u8, 105u8, 110u8, 105u8, 110u8, 103u8, 84u8, 121u8, 112u8, 101u8, 18u8, 41u8, 10u8,\n    16u8, 101u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 95u8, 110u8,\n    117u8, 109u8, 98u8, 101u8, 114u8, 24u8, 2u8, 32u8, 1u8, 40u8, 5u8, 82u8, 15u8, 101u8,\n    120u8, 116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8,\n    101u8, 114u8, 34u8, 199u8, 4u8, 10u8, 24u8, 83u8, 101u8, 114u8, 118u8, 101u8, 114u8,\n    82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 82u8, 101u8,\n    115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 29u8, 10u8, 10u8, 118u8, 97u8, 108u8,\n    105u8, 100u8, 95u8, 104u8, 111u8, 115u8, 116u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8,\n    82u8, 9u8, 118u8, 97u8, 108u8, 105u8, 100u8, 72u8, 111u8, 115u8, 116u8, 18u8, 91u8,\n    10u8, 16u8, 111u8, 114u8, 105u8, 103u8, 105u8, 110u8, 97u8, 108u8, 95u8, 114u8,\n    101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 24u8, 2u8, 32u8, 1u8, 40u8, 11u8, 50u8,\n    48u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8,\n    116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 97u8, 108u8, 112u8, 104u8, 97u8, 46u8,\n    83u8, 101u8, 114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8,\n    116u8, 105u8, 111u8, 110u8, 82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 82u8,\n    15u8, 111u8, 114u8, 105u8, 103u8, 105u8, 110u8, 97u8, 108u8, 82u8, 101u8, 113u8,\n    117u8, 101u8, 115u8, 116u8, 18u8, 107u8, 10u8, 24u8, 102u8, 105u8, 108u8, 101u8,\n    95u8, 100u8, 101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 95u8,\n    114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 24u8, 4u8, 32u8, 1u8, 40u8,\n    11u8, 50u8, 47u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8,\n    101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 97u8, 108u8, 112u8,\n    104u8, 97u8, 46u8, 70u8, 105u8, 108u8, 101u8, 68u8, 101u8, 115u8, 99u8, 114u8, 105u8,\n    112u8, 116u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8,\n    72u8, 0u8, 82u8, 22u8, 102u8, 105u8, 108u8, 101u8, 68u8, 101u8, 115u8, 99u8, 114u8,\n    105u8, 112u8, 116u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8,\n    101u8, 18u8, 119u8, 10u8, 30u8, 97u8, 108u8, 108u8, 95u8, 101u8, 120u8, 116u8, 101u8,\n    110u8, 115u8, 105u8, 111u8, 110u8, 95u8, 110u8, 117u8, 109u8, 98u8, 101u8, 114u8,\n    115u8, 95u8, 114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 24u8, 5u8, 32u8,\n    1u8, 40u8, 11u8, 50u8, 48u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8,\n    102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 97u8,\n    108u8, 112u8, 104u8, 97u8, 46u8, 69u8, 120u8, 116u8, 101u8, 110u8, 115u8, 105u8,\n    111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 72u8, 0u8, 82u8, 27u8, 97u8, 108u8, 108u8, 69u8, 120u8,\n    116u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8,\n    114u8, 115u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 100u8,\n    10u8, 22u8, 108u8, 105u8, 115u8, 116u8, 95u8, 115u8, 101u8, 114u8, 118u8, 105u8,\n    99u8, 101u8, 115u8, 95u8, 114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8,\n    24u8, 6u8, 32u8, 1u8, 40u8, 11u8, 50u8, 44u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8,\n    114u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8,\n    49u8, 97u8, 108u8, 112u8, 104u8, 97u8, 46u8, 76u8, 105u8, 115u8, 116u8, 83u8, 101u8,\n    114u8, 118u8, 105u8, 99u8, 101u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8,\n    101u8, 72u8, 0u8, 82u8, 20u8, 108u8, 105u8, 115u8, 116u8, 83u8, 101u8, 114u8, 118u8,\n    105u8, 99u8, 101u8, 115u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8,\n    18u8, 79u8, 10u8, 14u8, 101u8, 114u8, 114u8, 111u8, 114u8, 95u8, 114u8, 101u8, 115u8,\n    112u8, 111u8, 110u8, 115u8, 101u8, 24u8, 7u8, 32u8, 1u8, 40u8, 11u8, 50u8, 38u8,\n    46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8, 99u8,\n    116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 97u8, 108u8, 112u8, 104u8, 97u8, 46u8,\n    69u8, 114u8, 114u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8,\n    101u8, 72u8, 0u8, 82u8, 13u8, 101u8, 114u8, 114u8, 111u8, 114u8, 82u8, 101u8, 115u8,\n    112u8, 111u8, 110u8, 115u8, 101u8, 66u8, 18u8, 10u8, 16u8, 109u8, 101u8, 115u8,\n    115u8, 97u8, 103u8, 101u8, 95u8, 114u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8,\n    101u8, 34u8, 76u8, 10u8, 22u8, 70u8, 105u8, 108u8, 101u8, 68u8, 101u8, 115u8, 99u8,\n    114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8,\n    115u8, 101u8, 18u8, 50u8, 10u8, 21u8, 102u8, 105u8, 108u8, 101u8, 95u8, 100u8, 101u8,\n    115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 95u8, 112u8, 114u8, 111u8,\n    116u8, 111u8, 24u8, 1u8, 32u8, 3u8, 40u8, 12u8, 82u8, 19u8, 102u8, 105u8, 108u8,\n    101u8, 68u8, 101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 111u8, 114u8, 80u8,\n    114u8, 111u8, 116u8, 111u8, 34u8, 106u8, 10u8, 23u8, 69u8, 120u8, 116u8, 101u8,\n    110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 82u8,\n    101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 36u8, 10u8, 14u8, 98u8, 97u8,\n    115u8, 101u8, 95u8, 116u8, 121u8, 112u8, 101u8, 95u8, 110u8, 97u8, 109u8, 101u8,\n    24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 12u8, 98u8, 97u8, 115u8, 101u8, 84u8, 121u8,\n    112u8, 101u8, 78u8, 97u8, 109u8, 101u8, 18u8, 41u8, 10u8, 16u8, 101u8, 120u8, 116u8,\n    101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 95u8, 110u8, 117u8, 109u8, 98u8, 101u8,\n    114u8, 24u8, 2u8, 32u8, 3u8, 40u8, 5u8, 82u8, 15u8, 101u8, 120u8, 116u8, 101u8,\n    110u8, 115u8, 105u8, 111u8, 110u8, 78u8, 117u8, 109u8, 98u8, 101u8, 114u8, 34u8,\n    89u8, 10u8, 19u8, 76u8, 105u8, 115u8, 116u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8,\n    101u8, 82u8, 101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 66u8, 10u8, 7u8,\n    115u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 24u8, 1u8, 32u8, 3u8, 40u8, 11u8,\n    50u8, 40u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8, 101u8, 102u8, 108u8, 101u8,\n    99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8, 97u8, 108u8, 112u8, 104u8, 97u8,\n    46u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 82u8, 7u8, 115u8, 101u8, 114u8, 118u8, 105u8, 99u8,\n    101u8, 34u8, 37u8, 10u8, 15u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 82u8,\n    101u8, 115u8, 112u8, 111u8, 110u8, 115u8, 101u8, 18u8, 18u8, 10u8, 4u8, 110u8, 97u8,\n    109u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 4u8, 110u8, 97u8, 109u8, 101u8,\n    34u8, 83u8, 10u8, 13u8, 69u8, 114u8, 114u8, 111u8, 114u8, 82u8, 101u8, 115u8, 112u8,\n    111u8, 110u8, 115u8, 101u8, 18u8, 29u8, 10u8, 10u8, 101u8, 114u8, 114u8, 111u8,\n    114u8, 95u8, 99u8, 111u8, 100u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 5u8, 82u8, 9u8,\n    101u8, 114u8, 114u8, 111u8, 114u8, 67u8, 111u8, 100u8, 101u8, 18u8, 35u8, 10u8, 13u8,\n    101u8, 114u8, 114u8, 111u8, 114u8, 95u8, 109u8, 101u8, 115u8, 115u8, 97u8, 103u8,\n    101u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 12u8, 101u8, 114u8, 114u8, 111u8,\n    114u8, 77u8, 101u8, 115u8, 115u8, 97u8, 103u8, 101u8, 50u8, 147u8, 1u8, 10u8, 16u8,\n    83u8, 101u8, 114u8, 118u8, 101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8,\n    116u8, 105u8, 111u8, 110u8, 18u8, 127u8, 10u8, 20u8, 83u8, 101u8, 114u8, 118u8,\n    101u8, 114u8, 82u8, 101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8,\n    73u8, 110u8, 102u8, 111u8, 18u8, 48u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8,\n    101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8,\n    97u8, 108u8, 112u8, 104u8, 97u8, 46u8, 83u8, 101u8, 114u8, 118u8, 101u8, 114u8, 82u8,\n    101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 82u8, 101u8, 113u8,\n    117u8, 101u8, 115u8, 116u8, 26u8, 49u8, 46u8, 103u8, 114u8, 112u8, 99u8, 46u8, 114u8,\n    101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 46u8, 118u8, 49u8,\n    97u8, 108u8, 112u8, 104u8, 97u8, 46u8, 83u8, 101u8, 114u8, 118u8, 101u8, 114u8, 82u8,\n    101u8, 102u8, 108u8, 101u8, 99u8, 116u8, 105u8, 111u8, 110u8, 82u8, 101u8, 115u8,\n    112u8, 111u8, 110u8, 115u8, 101u8, 40u8, 1u8, 48u8, 1u8, 98u8, 6u8, 112u8, 114u8,\n    111u8, 116u8, 111u8, 51u8,\n];\n"
  },
  {
    "path": "tonic-reflection/src/lib.rs",
    "content": "//! A `tonic` based gRPC Server Reflection implementation.\n\n#![doc(\n    html_logo_url = \"https://github.com/hyperium/tonic/raw/master/.github/assets/tonic-docs.png\"\n)]\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nmod generated {\n    #![allow(unreachable_pub)]\n    #![allow(missing_docs)]\n    #![allow(rustdoc::invalid_html_tags)]\n\n    #[rustfmt::skip]\n    pub mod grpc_reflection_v1alpha;\n\n    #[rustfmt::skip]\n    pub mod grpc_reflection_v1;\n\n    #[rustfmt::skip]\n    pub mod reflection_v1_fds;\n\n    #[rustfmt::skip]\n    pub mod reflection_v1alpha1_fds;\n\n    pub use reflection_v1_fds::FILE_DESCRIPTOR_SET as FILE_DESCRIPTOR_SET_V1;\n    pub use reflection_v1alpha1_fds::FILE_DESCRIPTOR_SET as FILE_DESCRIPTOR_SET_V1ALPHA;\n\n    #[cfg(test)]\n    mod tests {\n        use super::{FILE_DESCRIPTOR_SET_V1, FILE_DESCRIPTOR_SET_V1ALPHA};\n        use prost::Message as _;\n\n        #[test]\n        fn v1alpha_file_descriptor_set_is_valid() {\n            prost_types::FileDescriptorSet::decode(FILE_DESCRIPTOR_SET_V1ALPHA).unwrap();\n        }\n\n        #[test]\n        fn v1_file_descriptor_set_is_valid() {\n            prost_types::FileDescriptorSet::decode(FILE_DESCRIPTOR_SET_V1).unwrap();\n        }\n    }\n}\n\n/// Generated protobuf types from the `grpc.reflection` namespace.\npub mod pb {\n    /// Generated protobuf types from the `grpc.reflection.v1` package.\n    pub mod v1 {\n        pub use crate::generated::{\n            FILE_DESCRIPTOR_SET_V1 as FILE_DESCRIPTOR_SET, grpc_reflection_v1::*,\n        };\n    }\n\n    /// Generated protobuf types from the `grpc.reflection.v1alpha` package.\n    pub mod v1alpha {\n        pub use crate::generated::{\n            FILE_DESCRIPTOR_SET_V1ALPHA as FILE_DESCRIPTOR_SET, grpc_reflection_v1alpha::*,\n        };\n    }\n}\n\n/// Implementation of the server component of gRPC Server Reflection.\n#[cfg(feature = \"server\")]\npub mod server;\n"
  },
  {
    "path": "tonic-reflection/src/server/mod.rs",
    "content": "use std::collections::HashMap;\nuse std::fmt::{Display, Formatter};\nuse std::sync::Arc;\n\nuse prost::{DecodeError, Message};\nuse prost_types::{\n    DescriptorProto, EnumDescriptorProto, FieldDescriptorProto, FileDescriptorProto,\n    FileDescriptorSet,\n};\nuse tonic::Status;\n\n/// v1 interface for the gRPC Reflection Service server.\npub mod v1;\n/// v1alpha interface for the gRPC Reflection Service server.\npub mod v1alpha;\n\n/// A builder used to construct a gRPC Reflection Service.\n#[derive(Debug)]\npub struct Builder<'b> {\n    file_descriptor_sets: Vec<FileDescriptorSet>,\n    encoded_file_descriptor_sets: Vec<&'b [u8]>,\n    include_reflection_service: bool,\n\n    service_names: Vec<String>,\n    use_all_service_names: bool,\n}\n\nimpl<'b> Builder<'b> {\n    /// Create a new builder that can configure a gRPC Reflection Service.\n    pub fn configure() -> Self {\n        Builder {\n            file_descriptor_sets: Vec::new(),\n            encoded_file_descriptor_sets: Vec::new(),\n            include_reflection_service: true,\n\n            service_names: Vec::new(),\n            use_all_service_names: true,\n        }\n    }\n\n    /// Registers an instance of `prost_types::FileDescriptorSet` with the gRPC Reflection\n    /// Service builder.\n    pub fn register_file_descriptor_set(mut self, file_descriptor_set: FileDescriptorSet) -> Self {\n        self.file_descriptor_sets.push(file_descriptor_set);\n        self\n    }\n\n    /// Registers a byte slice containing an encoded `prost_types::FileDescriptorSet` with\n    /// the gRPC Reflection Service builder.\n    pub fn register_encoded_file_descriptor_set(\n        mut self,\n        encoded_file_descriptor_set: &'b [u8],\n    ) -> Self {\n        self.encoded_file_descriptor_sets\n            .push(encoded_file_descriptor_set);\n        self\n    }\n\n    /// Serve the gRPC Reflection Service descriptor via the Reflection Service. This is enabled\n    /// by default - set `include` to false to disable.\n    pub fn include_reflection_service(mut self, include: bool) -> Self {\n        self.include_reflection_service = include;\n        self\n    }\n\n    /// Advertise a fully-qualified gRPC service name.\n    ///\n    /// If not called, then all services present in the registered file descriptor sets\n    /// will be advertised.\n    pub fn with_service_name(mut self, name: impl Into<String>) -> Self {\n        self.use_all_service_names = false;\n        self.service_names.push(name.into());\n        self\n    }\n\n    /// Build a v1 gRPC Reflection Service to be served via Tonic.\n    pub fn build_v1(\n        mut self,\n    ) -> Result<v1::ServerReflectionServer<impl v1::ServerReflection>, Error> {\n        if self.include_reflection_service {\n            self = self.register_encoded_file_descriptor_set(crate::pb::v1::FILE_DESCRIPTOR_SET);\n        }\n\n        Ok(v1::ServerReflectionServer::new(\n            v1::ReflectionService::from(ReflectionServiceState::new(\n                self.service_names,\n                self.encoded_file_descriptor_sets,\n                self.file_descriptor_sets,\n                self.use_all_service_names,\n            )?),\n        ))\n    }\n\n    /// Build a v1alpha gRPC Reflection Service to be served via Tonic.\n    pub fn build_v1alpha(\n        mut self,\n    ) -> Result<v1alpha::ServerReflectionServer<impl v1alpha::ServerReflection>, Error> {\n        if self.include_reflection_service {\n            self =\n                self.register_encoded_file_descriptor_set(crate::pb::v1alpha::FILE_DESCRIPTOR_SET);\n        }\n\n        Ok(v1alpha::ServerReflectionServer::new(\n            v1alpha::ReflectionService::from(ReflectionServiceState::new(\n                self.service_names,\n                self.encoded_file_descriptor_sets,\n                self.file_descriptor_sets,\n                self.use_all_service_names,\n            )?),\n        ))\n    }\n}\n\n#[derive(Debug)]\nstruct ReflectionServiceState {\n    service_names: Vec<String>,\n    files: HashMap<String, Arc<FileDescriptorProto>>,\n    symbols: HashMap<String, Arc<FileDescriptorProto>>,\n}\n\nimpl ReflectionServiceState {\n    fn new(\n        service_names: Vec<String>,\n        encoded_file_descriptor_sets: Vec<&[u8]>,\n        mut file_descriptor_sets: Vec<FileDescriptorSet>,\n        use_all_service_names: bool,\n    ) -> Result<Self, Error> {\n        for encoded in encoded_file_descriptor_sets {\n            file_descriptor_sets.push(FileDescriptorSet::decode(encoded)?);\n        }\n\n        let mut state = ReflectionServiceState {\n            service_names,\n            files: HashMap::new(),\n            symbols: HashMap::new(),\n        };\n\n        for fds in file_descriptor_sets {\n            for fd in fds.file {\n                let name = match fd.name.clone() {\n                    None => {\n                        return Err(Error::InvalidFileDescriptorSet(\"missing name\".to_string()));\n                    }\n                    Some(n) => n,\n                };\n\n                if state.files.contains_key(&name) {\n                    continue;\n                }\n\n                let fd = Arc::new(fd);\n                state.files.insert(name, fd.clone());\n                state.process_file(fd, use_all_service_names)?;\n            }\n        }\n\n        Ok(state)\n    }\n\n    fn process_file(\n        &mut self,\n        fd: Arc<FileDescriptorProto>,\n        use_all_service_names: bool,\n    ) -> Result<(), Error> {\n        let prefix = &fd.package.clone().unwrap_or_default();\n\n        for msg in &fd.message_type {\n            self.process_message(fd.clone(), prefix, msg)?;\n        }\n\n        for en in &fd.enum_type {\n            self.process_enum(fd.clone(), prefix, en)?;\n        }\n\n        for service in &fd.service {\n            let service_name = extract_name(prefix, \"service\", service.name.as_ref())?;\n            if use_all_service_names {\n                self.service_names.push(service_name.clone());\n            }\n            self.symbols.insert(service_name.clone(), fd.clone());\n\n            for method in &service.method {\n                let method_name = extract_name(&service_name, \"method\", method.name.as_ref())?;\n                self.symbols.insert(method_name, fd.clone());\n            }\n        }\n\n        Ok(())\n    }\n\n    fn process_message(\n        &mut self,\n        fd: Arc<FileDescriptorProto>,\n        prefix: &str,\n        msg: &DescriptorProto,\n    ) -> Result<(), Error> {\n        let message_name = extract_name(prefix, \"message\", msg.name.as_ref())?;\n        self.symbols.insert(message_name.clone(), fd.clone());\n\n        for nested in &msg.nested_type {\n            self.process_message(fd.clone(), &message_name, nested)?;\n        }\n\n        for en in &msg.enum_type {\n            self.process_enum(fd.clone(), &message_name, en)?;\n        }\n\n        for field in &msg.field {\n            self.process_field(fd.clone(), &message_name, field)?;\n        }\n\n        for oneof in &msg.oneof_decl {\n            let oneof_name = extract_name(&message_name, \"oneof\", oneof.name.as_ref())?;\n            self.symbols.insert(oneof_name, fd.clone());\n        }\n\n        Ok(())\n    }\n\n    fn process_enum(\n        &mut self,\n        fd: Arc<FileDescriptorProto>,\n        prefix: &str,\n        en: &EnumDescriptorProto,\n    ) -> Result<(), Error> {\n        let enum_name = extract_name(prefix, \"enum\", en.name.as_ref())?;\n        self.symbols.insert(enum_name.clone(), fd.clone());\n\n        for value in &en.value {\n            let value_name = extract_name(&enum_name, \"enum value\", value.name.as_ref())?;\n            self.symbols.insert(value_name, fd.clone());\n        }\n\n        Ok(())\n    }\n\n    fn process_field(\n        &mut self,\n        fd: Arc<FileDescriptorProto>,\n        prefix: &str,\n        field: &FieldDescriptorProto,\n    ) -> Result<(), Error> {\n        let field_name = extract_name(prefix, \"field\", field.name.as_ref())?;\n        self.symbols.insert(field_name, fd);\n        Ok(())\n    }\n\n    fn list_services(&self) -> &[String] {\n        &self.service_names\n    }\n\n    fn symbol_by_name(&self, symbol: &str) -> Result<Vec<u8>, Status> {\n        match self.symbols.get(symbol) {\n            None => Err(Status::not_found(format!(\"symbol '{symbol}' not found\"))),\n            Some(fd) => {\n                let mut encoded_fd = Vec::new();\n                if fd.clone().encode(&mut encoded_fd).is_err() {\n                    return Err(Status::internal(\"encoding error\"));\n                };\n\n                Ok(encoded_fd)\n            }\n        }\n    }\n\n    fn file_by_filename(&self, filename: &str) -> Result<Vec<u8>, Status> {\n        match self.files.get(filename) {\n            None => Err(Status::not_found(format!(\"file '{filename}' not found\"))),\n            Some(fd) => {\n                let mut encoded_fd = Vec::new();\n                if fd.clone().encode(&mut encoded_fd).is_err() {\n                    return Err(Status::internal(\"encoding error\"));\n                }\n\n                Ok(encoded_fd)\n            }\n        }\n    }\n}\n\nfn extract_name(\n    prefix: &str,\n    name_type: &str,\n    maybe_name: Option<&String>,\n) -> Result<String, Error> {\n    match maybe_name {\n        None => Err(Error::InvalidFileDescriptorSet(format!(\n            \"missing {name_type} name\"\n        ))),\n        Some(name) => {\n            if prefix.is_empty() {\n                Ok(name.to_string())\n            } else {\n                Ok(format!(\"{prefix}.{name}\"))\n            }\n        }\n    }\n}\n\n/// Represents an error in the construction of a gRPC Reflection Service.\n#[derive(Debug)]\npub enum Error {\n    /// An error was encountered decoding a `prost_types::FileDescriptorSet` from a buffer.\n    DecodeError(prost::DecodeError),\n    /// An invalid `prost_types::FileDescriptorProto` was encountered.\n    InvalidFileDescriptorSet(String),\n}\n\nimpl From<DecodeError> for Error {\n    fn from(e: DecodeError) -> Self {\n        Error::DecodeError(e)\n    }\n}\n\nimpl std::error::Error for Error {}\n\nimpl Display for Error {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Error::DecodeError(_) => f.write_str(\"error decoding FileDescriptorSet from buffer\"),\n            Error::InvalidFileDescriptorSet(s) => {\n                write!(f, \"invalid FileDescriptorSet - {s}\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-reflection/src/server/v1.rs",
    "content": "use std::{fmt, sync::Arc};\n\nuse tokio::sync::mpsc;\nuse tokio_stream::{Stream, StreamExt};\nuse tonic::{Request, Response, Status, Streaming};\n\nuse super::ReflectionServiceState;\nuse crate::pb::v1::server_reflection_request::MessageRequest;\nuse crate::pb::v1::server_reflection_response::MessageResponse;\npub use crate::pb::v1::server_reflection_server::{ServerReflection, ServerReflectionServer};\nuse crate::pb::v1::{\n    ExtensionNumberResponse, FileDescriptorResponse, ListServiceResponse, ServerReflectionRequest,\n    ServerReflectionResponse, ServiceResponse,\n};\n\n/// An implementation for `ServerReflection`.\n#[derive(Debug)]\npub struct ReflectionService {\n    state: Arc<ReflectionServiceState>,\n}\n\n#[tonic::async_trait]\nimpl ServerReflection for ReflectionService {\n    type ServerReflectionInfoStream = ServerReflectionInfoStream;\n\n    async fn server_reflection_info(\n        &self,\n        req: Request<Streaming<ServerReflectionRequest>>,\n    ) -> Result<Response<Self::ServerReflectionInfoStream>, Status> {\n        let mut req_rx = req.into_inner();\n        let (resp_tx, resp_rx) = mpsc::channel::<Result<ServerReflectionResponse, Status>>(1);\n\n        let state = self.state.clone();\n\n        tokio::spawn(async move {\n            while let Some(req) = req_rx.next().await {\n                let Ok(req) = req else {\n                    return;\n                };\n\n                let resp_msg = match req.message_request.clone() {\n                    None => Err(Status::invalid_argument(\"invalid MessageRequest\")),\n                    Some(msg) => match msg {\n                        MessageRequest::FileByFilename(s) => state.file_by_filename(&s).map(|fd| {\n                            MessageResponse::FileDescriptorResponse(FileDescriptorResponse {\n                                file_descriptor_proto: vec![fd],\n                            })\n                        }),\n                        MessageRequest::FileContainingSymbol(s) => {\n                            state.symbol_by_name(&s).map(|fd| {\n                                MessageResponse::FileDescriptorResponse(FileDescriptorResponse {\n                                    file_descriptor_proto: vec![fd],\n                                })\n                            })\n                        }\n                        MessageRequest::FileContainingExtension(_) => {\n                            Err(Status::not_found(\"extensions are not supported\"))\n                        }\n                        MessageRequest::AllExtensionNumbersOfType(_) => {\n                            // NOTE: Workaround. Some grpc clients (e.g. grpcurl) expect this method not to fail.\n                            // https://github.com/hyperium/tonic/issues/1077\n                            Ok(MessageResponse::AllExtensionNumbersResponse(\n                                ExtensionNumberResponse::default(),\n                            ))\n                        }\n                        MessageRequest::ListServices(_) => {\n                            Ok(MessageResponse::ListServicesResponse(ListServiceResponse {\n                                service: state\n                                    .list_services()\n                                    .iter()\n                                    .map(|s| ServiceResponse { name: s.clone() })\n                                    .collect(),\n                            }))\n                        }\n                    },\n                };\n\n                match resp_msg {\n                    Ok(resp_msg) => {\n                        let resp = ServerReflectionResponse {\n                            valid_host: req.host.clone(),\n                            original_request: Some(req.clone()),\n                            message_response: Some(resp_msg),\n                        };\n                        resp_tx.send(Ok(resp)).await.expect(\"send\");\n                    }\n                    Err(status) => {\n                        resp_tx.send(Err(status)).await.expect(\"send\");\n                        return;\n                    }\n                }\n            }\n        });\n\n        Ok(Response::new(ServerReflectionInfoStream::new(resp_rx)))\n    }\n}\n\nimpl From<ReflectionServiceState> for ReflectionService {\n    fn from(state: ReflectionServiceState) -> Self {\n        Self {\n            state: Arc::new(state),\n        }\n    }\n}\n\n/// A response stream.\npub struct ServerReflectionInfoStream {\n    inner: tokio_stream::wrappers::ReceiverStream<Result<ServerReflectionResponse, Status>>,\n}\n\nimpl ServerReflectionInfoStream {\n    fn new(resp_rx: mpsc::Receiver<Result<ServerReflectionResponse, Status>>) -> Self {\n        let inner = tokio_stream::wrappers::ReceiverStream::new(resp_rx);\n        Self { inner }\n    }\n}\n\nimpl Stream for ServerReflectionInfoStream {\n    type Item = Result<ServerReflectionResponse, Status>;\n\n    fn poll_next(\n        mut self: std::pin::Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Option<Self::Item>> {\n        std::pin::Pin::new(&mut self.inner).poll_next(cx)\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\nimpl fmt::Debug for ServerReflectionInfoStream {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_tuple(\"ServerReflectionInfoStream\").finish()\n    }\n}\n"
  },
  {
    "path": "tonic-reflection/src/server/v1alpha.rs",
    "content": "use std::{fmt, sync::Arc};\n\nuse tokio::sync::mpsc;\nuse tokio_stream::{Stream, StreamExt};\nuse tonic::{Request, Response, Status, Streaming};\n\nuse super::ReflectionServiceState;\nuse crate::pb::v1alpha::server_reflection_request::MessageRequest;\nuse crate::pb::v1alpha::server_reflection_response::MessageResponse;\npub use crate::pb::v1alpha::server_reflection_server::{ServerReflection, ServerReflectionServer};\nuse crate::pb::v1alpha::{\n    ExtensionNumberResponse, FileDescriptorResponse, ListServiceResponse, ServerReflectionRequest,\n    ServerReflectionResponse, ServiceResponse,\n};\n\n/// An implementation for `ServerReflection`.\n#[derive(Debug)]\npub struct ReflectionService {\n    state: Arc<ReflectionServiceState>,\n}\n\n#[tonic::async_trait]\nimpl ServerReflection for ReflectionService {\n    type ServerReflectionInfoStream = ServerReflectionInfoStream;\n\n    async fn server_reflection_info(\n        &self,\n        req: Request<Streaming<ServerReflectionRequest>>,\n    ) -> Result<Response<Self::ServerReflectionInfoStream>, Status> {\n        let mut req_rx = req.into_inner();\n        let (resp_tx, resp_rx) = mpsc::channel::<Result<ServerReflectionResponse, Status>>(1);\n\n        let state = self.state.clone();\n\n        tokio::spawn(async move {\n            while let Some(req) = req_rx.next().await {\n                let Ok(req) = req else {\n                    return;\n                };\n\n                let resp_msg = match req.message_request.clone() {\n                    None => Err(Status::invalid_argument(\"invalid MessageRequest\")),\n                    Some(msg) => match msg {\n                        MessageRequest::FileByFilename(s) => state.file_by_filename(&s).map(|fd| {\n                            MessageResponse::FileDescriptorResponse(FileDescriptorResponse {\n                                file_descriptor_proto: vec![fd],\n                            })\n                        }),\n                        MessageRequest::FileContainingSymbol(s) => {\n                            state.symbol_by_name(&s).map(|fd| {\n                                MessageResponse::FileDescriptorResponse(FileDescriptorResponse {\n                                    file_descriptor_proto: vec![fd],\n                                })\n                            })\n                        }\n                        MessageRequest::FileContainingExtension(_) => {\n                            Err(Status::not_found(\"extensions are not supported\"))\n                        }\n                        MessageRequest::AllExtensionNumbersOfType(_) => {\n                            // NOTE: Workaround. Some grpc clients (e.g. grpcurl) expect this method not to fail.\n                            // https://github.com/hyperium/tonic/issues/1077\n                            Ok(MessageResponse::AllExtensionNumbersResponse(\n                                ExtensionNumberResponse::default(),\n                            ))\n                        }\n                        MessageRequest::ListServices(_) => {\n                            Ok(MessageResponse::ListServicesResponse(ListServiceResponse {\n                                service: state\n                                    .list_services()\n                                    .iter()\n                                    .map(|s| ServiceResponse { name: s.clone() })\n                                    .collect(),\n                            }))\n                        }\n                    },\n                };\n\n                match resp_msg {\n                    Ok(resp_msg) => {\n                        let resp = ServerReflectionResponse {\n                            valid_host: req.host.clone(),\n                            original_request: Some(req.clone()),\n                            message_response: Some(resp_msg),\n                        };\n                        resp_tx.send(Ok(resp)).await.expect(\"send\");\n                    }\n                    Err(status) => {\n                        resp_tx.send(Err(status)).await.expect(\"send\");\n                        return;\n                    }\n                }\n            }\n        });\n\n        Ok(Response::new(ServerReflectionInfoStream::new(resp_rx)))\n    }\n}\n\nimpl From<ReflectionServiceState> for ReflectionService {\n    fn from(state: ReflectionServiceState) -> Self {\n        Self {\n            state: Arc::new(state),\n        }\n    }\n}\n\n/// A response stream.\npub struct ServerReflectionInfoStream {\n    inner: tokio_stream::wrappers::ReceiverStream<Result<ServerReflectionResponse, Status>>,\n}\n\nimpl ServerReflectionInfoStream {\n    fn new(resp_rx: mpsc::Receiver<Result<ServerReflectionResponse, Status>>) -> Self {\n        let inner = tokio_stream::wrappers::ReceiverStream::new(resp_rx);\n        Self { inner }\n    }\n}\n\nimpl Stream for ServerReflectionInfoStream {\n    type Item = Result<ServerReflectionResponse, Status>;\n\n    fn poll_next(\n        mut self: std::pin::Pin<&mut Self>,\n        cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Option<Self::Item>> {\n        std::pin::Pin::new(&mut self.inner).poll_next(cx)\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.inner.size_hint()\n    }\n}\n\nimpl fmt::Debug for ServerReflectionInfoStream {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_tuple(\"ServerReflectionInfoStream\").finish()\n    }\n}\n"
  },
  {
    "path": "tonic-reflection/tests/server.rs",
    "content": "#![allow(missing_docs)]\n\nuse prost::Message;\nuse std::net::SocketAddr;\nuse tokio::sync::oneshot;\nuse tokio_stream::{StreamExt, wrappers::TcpListenerStream};\nuse tonic::{Request, transport::Server};\nuse tonic_reflection::{\n    pb::v1::{\n        FILE_DESCRIPTOR_SET, ServerReflectionRequest, ServiceResponse,\n        server_reflection_client::ServerReflectionClient,\n        server_reflection_request::MessageRequest, server_reflection_response::MessageResponse,\n    },\n    server::Builder,\n};\n\npub(crate) fn get_encoded_reflection_service_fd() -> Vec<u8> {\n    let mut expected = Vec::new();\n    prost_types::FileDescriptorSet::decode(FILE_DESCRIPTOR_SET)\n        .expect(\"decode reflection service file descriptor set\")\n        .file[0]\n        .encode(&mut expected)\n        .expect(\"encode reflection service file descriptor\");\n    expected\n}\n\n#[tokio::test]\nasync fn test_list_services() {\n    let response = make_test_reflection_request(ServerReflectionRequest {\n        host: \"\".to_string(),\n        message_request: Some(MessageRequest::ListServices(String::new())),\n    })\n    .await;\n\n    if let MessageResponse::ListServicesResponse(services) = response {\n        assert_eq!(\n            services.service,\n            vec![ServiceResponse {\n                name: String::from(\"grpc.reflection.v1.ServerReflection\")\n            }]\n        );\n    } else {\n        panic!(\"Expected a ListServicesResponse variant\");\n    }\n}\n\n#[tokio::test]\nasync fn test_file_by_filename() {\n    let response = make_test_reflection_request(ServerReflectionRequest {\n        host: \"\".to_string(),\n        message_request: Some(MessageRequest::FileByFilename(String::from(\n            \"reflection_v1.proto\",\n        ))),\n    })\n    .await;\n\n    if let MessageResponse::FileDescriptorResponse(descriptor) = response {\n        let file_descriptor_proto = descriptor\n            .file_descriptor_proto\n            .first()\n            .expect(\"descriptor\");\n        assert_eq!(\n            file_descriptor_proto.as_ref(),\n            get_encoded_reflection_service_fd()\n        );\n    } else {\n        panic!(\"Expected a FileDescriptorResponse variant\");\n    }\n}\n\n#[tokio::test]\nasync fn test_file_containing_symbol() {\n    let response = make_test_reflection_request(ServerReflectionRequest {\n        host: \"\".to_string(),\n        message_request: Some(MessageRequest::FileContainingSymbol(String::from(\n            \"grpc.reflection.v1.ServerReflection\",\n        ))),\n    })\n    .await;\n\n    if let MessageResponse::FileDescriptorResponse(descriptor) = response {\n        let file_descriptor_proto = descriptor\n            .file_descriptor_proto\n            .first()\n            .expect(\"descriptor\");\n        assert_eq!(\n            file_descriptor_proto.as_ref(),\n            get_encoded_reflection_service_fd()\n        );\n    } else {\n        panic!(\"Expected a FileDescriptorResponse variant\");\n    }\n}\n\nasync fn make_test_reflection_request(request: ServerReflectionRequest) -> MessageResponse {\n    // Run a test server\n    let (shutdown_tx, shutdown_rx) = oneshot::channel();\n\n    let addr: SocketAddr = \"127.0.0.1:0\".parse().expect(\"SocketAddr parse\");\n    let listener = tokio::net::TcpListener::bind(addr).await.expect(\"bind\");\n    let local_addr = format!(\"http://{}\", listener.local_addr().expect(\"local address\"));\n    let jh = tokio::spawn(async move {\n        let service = Builder::configure()\n            .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET)\n            .build_v1()\n            .unwrap();\n\n        Server::builder()\n            .add_service(service)\n            .serve_with_incoming_shutdown(TcpListenerStream::new(listener), async {\n                drop(shutdown_rx.await)\n            })\n            .await\n            .unwrap();\n    });\n\n    // Give the test server a few ms to become available\n    tokio::time::sleep(std::time::Duration::from_millis(100)).await;\n\n    // Construct client and send request, extract response\n    let conn = tonic::transport::Endpoint::new(local_addr)\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n    let mut client = ServerReflectionClient::new(conn);\n\n    let request = Request::new(tokio_stream::once(request));\n    let mut inbound = client\n        .server_reflection_info(request)\n        .await\n        .expect(\"request\")\n        .into_inner();\n\n    let response = inbound\n        .next()\n        .await\n        .expect(\"steamed response\")\n        .expect(\"successful response\")\n        .message_response\n        .expect(\"some MessageResponse\");\n\n    // We only expect one response per request\n    assert!(inbound.next().await.is_none());\n\n    // Shut down test server\n    shutdown_tx.send(()).expect(\"send shutdown\");\n    jh.await.expect(\"server shutdown\");\n\n    response\n}\n"
  },
  {
    "path": "tonic-reflection/tests/versions.rs",
    "content": "#![allow(missing_docs)]\n\nuse std::net::SocketAddr;\n\nuse tokio::sync::oneshot;\nuse tokio_stream::{StreamExt, wrappers::TcpListenerStream};\nuse tonic::{Request, transport::Server};\n\nuse tonic_reflection::pb::{v1, v1alpha};\nuse tonic_reflection::server::Builder;\n\n#[tokio::test]\nasync fn test_v1() {\n    let response = make_v1_request(v1::ServerReflectionRequest {\n        host: \"\".to_string(),\n        message_request: Some(v1::server_reflection_request::MessageRequest::ListServices(\n            String::new(),\n        )),\n    })\n    .await;\n\n    if let v1::server_reflection_response::MessageResponse::ListServicesResponse(services) =\n        response\n    {\n        assert_eq!(\n            services.service,\n            vec![v1::ServiceResponse {\n                name: String::from(\"grpc.reflection.v1.ServerReflection\")\n            }]\n        );\n    } else {\n        panic!(\"Expected a ListServicesResponse variant\");\n    }\n}\n\n#[tokio::test]\nasync fn test_v1alpha() {\n    let response = make_v1alpha_request(v1alpha::ServerReflectionRequest {\n        host: \"\".to_string(),\n        message_request: Some(\n            v1alpha::server_reflection_request::MessageRequest::ListServices(String::new()),\n        ),\n    })\n    .await;\n\n    if let v1alpha::server_reflection_response::MessageResponse::ListServicesResponse(services) =\n        response\n    {\n        assert_eq!(\n            services.service,\n            vec![v1alpha::ServiceResponse {\n                name: String::from(\"grpc.reflection.v1alpha.ServerReflection\")\n            }]\n        );\n    } else {\n        panic!(\"Expected a ListServicesResponse variant\");\n    }\n}\n\nasync fn make_v1_request(\n    request: v1::ServerReflectionRequest,\n) -> v1::server_reflection_response::MessageResponse {\n    // Run a test server\n    let (shutdown_tx, shutdown_rx) = oneshot::channel();\n\n    let addr: SocketAddr = \"127.0.0.1:0\".parse().expect(\"SocketAddr parse\");\n    let listener = tokio::net::TcpListener::bind(addr).await.expect(\"bind\");\n    let local_addr = format!(\"http://{}\", listener.local_addr().expect(\"local address\"));\n    let jh = tokio::spawn(async move {\n        let service = Builder::configure().build_v1().unwrap();\n\n        Server::builder()\n            .add_service(service)\n            .serve_with_incoming_shutdown(TcpListenerStream::new(listener), async {\n                drop(shutdown_rx.await)\n            })\n            .await\n            .unwrap();\n    });\n\n    // Give the test server a few ms to become available\n    tokio::time::sleep(std::time::Duration::from_millis(100)).await;\n\n    // Construct client and send request, extract response\n    let conn = tonic::transport::Endpoint::new(local_addr)\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n    let mut client = v1::server_reflection_client::ServerReflectionClient::new(conn);\n\n    let request = Request::new(tokio_stream::once(request));\n    let mut inbound = client\n        .server_reflection_info(request)\n        .await\n        .expect(\"request\")\n        .into_inner();\n\n    let response = inbound\n        .next()\n        .await\n        .expect(\"steamed response\")\n        .expect(\"successful response\")\n        .message_response\n        .expect(\"some MessageResponse\");\n\n    // We only expect one response per request\n    assert!(inbound.next().await.is_none());\n\n    // Shut down test server\n    shutdown_tx.send(()).expect(\"send shutdown\");\n    jh.await.expect(\"server shutdown\");\n\n    response\n}\n\nasync fn make_v1alpha_request(\n    request: v1alpha::ServerReflectionRequest,\n) -> v1alpha::server_reflection_response::MessageResponse {\n    // Run a test server\n    let (shutdown_tx, shutdown_rx) = oneshot::channel();\n\n    let addr: SocketAddr = \"127.0.0.1:0\".parse().expect(\"SocketAddr parse\");\n    let listener = tokio::net::TcpListener::bind(addr).await.expect(\"bind\");\n    let local_addr = format!(\"http://{}\", listener.local_addr().expect(\"local address\"));\n    let jh = tokio::spawn(async move {\n        let service = Builder::configure().build_v1alpha().unwrap();\n\n        Server::builder()\n            .add_service(service)\n            .serve_with_incoming_shutdown(TcpListenerStream::new(listener), async {\n                drop(shutdown_rx.await)\n            })\n            .await\n            .unwrap();\n    });\n\n    // Give the test server a few ms to become available\n    tokio::time::sleep(std::time::Duration::from_millis(100)).await;\n\n    // Construct client and send request, extract response\n    let conn = tonic::transport::Endpoint::new(local_addr)\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n    let mut client = v1alpha::server_reflection_client::ServerReflectionClient::new(conn);\n\n    let request = Request::new(tokio_stream::once(request));\n    let mut inbound = client\n        .server_reflection_info(request)\n        .await\n        .expect(\"request\")\n        .into_inner();\n\n    let response = inbound\n        .next()\n        .await\n        .expect(\"steamed response\")\n        .expect(\"successful response\")\n        .message_response\n        .expect(\"some MessageResponse\");\n\n    // We only expect one response per request\n    assert!(inbound.next().await.is_none());\n\n    // Shut down test server\n    shutdown_tx.send(()).expect(\"send shutdown\");\n    jh.await.expect(\"server shutdown\");\n\n    response\n}\n"
  },
  {
    "path": "tonic-types/Cargo.toml",
    "content": "[package]\nauthors = [\n  \"Lucio Franco <luciofranco14@gmail.com>\",\n  \"Rafael Lemos <flemos.rafael.dev@gmail.com>\"\n]\ncategories = [\"web-programming\", \"network-programming\", \"asynchronous\"]\ndescription = \"\"\"\nA collection of useful protobuf types that can be used with `tonic`.\n\"\"\"\nedition = \"2024\"\nhomepage = \"https://github.com/hyperium/tonic\"\nkeywords = [\"rpc\", \"grpc\", \"protobuf\"]\nlicense = \"MIT\"\nname = \"tonic-types\"\nreadme = \"README.md\"\nrepository = \"https://github.com/hyperium/tonic\"\nversion = \"0.14.5\"\nrust-version = { workspace = true }\n\n[dependencies]\nprost = \"0.14\"\nprost-types = \"0.14\"\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false }\n\n[lints]\nworkspace = true\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  \"tonic::*\",\n\n  # not major released\n  \"prost::*\",\n  \"prost_types::*\",\n]\n"
  },
  {
    "path": "tonic-types/README.md",
    "content": "# tonic-types\n\nA collection of useful protobuf types that can be used with `tonic`.\n\nThis crate also introduces the [`StatusExt`] trait and implements it in\n[`tonic::Status`], allowing the implementation of the [gRPC Richer Error Model] \nwith [`tonic`] in a convenient way.\n\n## Usage\n\nUseful protobuf types are available through the [`pb`] module. They can be\nimported and worked with directly.  \n\nThe [`StatusExt`] trait adds associated functions to [`tonic::Status`] that can\nbe used on the server side to create a status with error details, which can then\nbe returned to gRPC clients. Moreover, the trait also adds methods to\n[`tonic::Status`] that can be used by a tonic client to extract error details,\nand handle them with ease.\n\n## Examples\n\nThe examples below cover a basic use case of the [gRPC Richer Error Model].\nMore complete server and client implementations are provided in the\n**Richer Error example**, located in the main repo [examples] directory.\n\n### Server Side: Generating [`tonic::Status`] with an [`ErrorDetails`] struct\n\n```rust\nuse tonic::{Code, Status};\nuse tonic_types::{ErrorDetails, StatusExt};\n\n// ...\n// Inside a gRPC server endpoint that returns `Result<Response<T>, Status>`\n\n// Create empty `ErrorDetails` struct\nlet mut err_details = ErrorDetails::new();\n\n// Add error details conditionally\nif some_condition {\n    err_details.add_bad_request_violation(\n        \"field_a\",\n        \"description of why the field_a is invalid\"\n    );\n}\n\nif other_condition {\n    err_details.add_bad_request_violation(\n        \"field_b\",\n        \"description of why the field_b is invalid\",\n    );\n}\n\n// Check if any error details were set and return error status if so\nif err_details.has_bad_request_violations() {\n    // Add additional error details if necessary\n    err_details\n        .add_help_link(\"description of link\", \"https://resource.example.local\")\n        .set_localized_message(\"en-US\", \"message for the user\");\n\n    let status = Status::with_error_details(\n        Code::InvalidArgument,\n        \"bad request\",\n        err_details,\n    );\n    return Err(status);\n}\n\n// Handle valid request\n// ...\n```\n\n### Client Side: Extracting an [`ErrorDetails`] struct from [`tonic::Status`]\n\n```rust\nuse tonic::{Response, Status};\nuse tonic_types::StatusExt;\n\n// ...\n// Where `req_result` was returned by a gRPC client endpoint method\nfn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    match req_result {\n        Ok(response) => {\n            // Handle successful response\n        },\n        Err(status) => {\n            let err_details = status.get_error_details();\n            if let Some(bad_request) = err_details.bad_request() {\n                // Handle bad_request details\n            }\n            if let Some(help) = err_details.help() {\n                // Handle help details\n            }\n            if let Some(localized_message) = err_details.localized_message() {\n                // Handle localized_message details\n            }\n        }\n    };\n}\n```\n\n## Working with different error message types\n\nMultiple examples are provided at the [`ErrorDetails`] doc. Instructions about \nhow to use the fields of the standard error message types correctly are provided\nat [error_details.proto].\n\n## Alternative `tonic::Status` associated functions and methods\n\nIn the [`StatusExt`] doc, an alternative way of interacting with\n[`tonic::Status`] is presented, using vectors of error details structs wrapped\nwith the [`ErrorDetail`] enum. This approach can provide more control over the\nvector of standard error messages that will be generated or that was received,\nif necessary. To see how to adopt this approach, please check the\n[`StatusExt::with_error_details_vec`] and [`StatusExt::get_error_details_vec`]\ndocs, and also the main repo's [Richer Error example] directory.  \n\nBesides that, multiple examples with alternative error details extraction\nmethods are provided in the [`StatusExt`] doc, which can be specially\nuseful if only one type of standard error message is being handled by the\nclient. For example, using [`StatusExt::get_details_bad_request`] is a\nmore direct way of extracting a [`BadRequest`] error message from\n[`tonic::Status`].\n\n[`tonic::Status`]: https://docs.rs/tonic/latest/tonic/struct.Status.html\n[`tonic`]: https://docs.rs/tonic/latest/tonic/\n[gRPC Richer Error Model]: https://www.grpc.io/docs/guides/error/\n[`pb`]: https://docs.rs/tonic-types/latest/tonic_types/pb/index.html\n[`StatusExt`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html\n[examples]: https://github.com/hyperium/tonic/tree/master/examples\n[`ErrorDetails`]: https://docs.rs/tonic-types/latest/tonic_types/struct.ErrorDetails.html\n[error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n[`ErrorDetail`]: https://docs.rs/tonic-types/latest/tonic_types/enum.ErrorDetail.html\n[`StatusExt::with_error_details_vec`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html#tymethod.with_error_details_vec\n[`StatusExt::get_error_details_vec`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html#tymethod.get_error_details_vec\n[Richer Error example]: https://github.com/hyperium/tonic/tree/master/examples/src/richer-error\n[`StatusExt::get_details_bad_request`]: https://docs.rs/tonic-types/latest/tonic_types/trait.StatusExt.html#tymethod.get_details_bad_request\n[`BadRequest`]: https://docs.rs/tonic-types/latest/tonic_types/struct.BadRequest.html\n"
  },
  {
    "path": "tonic-types/proto/error_details.proto",
    "content": "// Copyright 2025 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.rpc;\n\nimport \"google/protobuf/duration.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/rpc/errdetails;errdetails\";\noption java_multiple_files = true;\noption java_outer_classname = \"ErrorDetailsProto\";\noption java_package = \"com.google.rpc\";\noption objc_class_prefix = \"RPC\";\n\n// Describes the cause of the error with structured details.\n//\n// Example of an error when contacting the \"pubsub.googleapis.com\" API when it\n// is not enabled:\n//\n//     { \"reason\": \"API_DISABLED\"\n//       \"domain\": \"googleapis.com\"\n//       \"metadata\": {\n//         \"resource\": \"projects/123\",\n//         \"service\": \"pubsub.googleapis.com\"\n//       }\n//     }\n//\n// This response indicates that the pubsub.googleapis.com API is not enabled.\n//\n// Example of an error that is returned when attempting to create a Spanner\n// instance in a region that is out of stock:\n//\n//     { \"reason\": \"STOCKOUT\"\n//       \"domain\": \"spanner.googleapis.com\",\n//       \"metadata\": {\n//         \"availableRegions\": \"us-central1,us-east2\"\n//       }\n//     }\nmessage ErrorInfo {\n  // The reason of the error. This is a constant value that identifies the\n  // proximate cause of the error. Error reasons are unique within a particular\n  // domain of errors. This should be at most 63 characters and match a\n  // regular expression of `[A-Z][A-Z0-9_]+[A-Z0-9]`, which represents\n  // UPPER_SNAKE_CASE.\n  string reason = 1;\n\n  // The logical grouping to which the \"reason\" belongs. The error domain\n  // is typically the registered service name of the tool or product that\n  // generates the error. Example: \"pubsub.googleapis.com\". If the error is\n  // generated by some common infrastructure, the error domain must be a\n  // globally unique value that identifies the infrastructure. For Google API\n  // infrastructure, the error domain is \"googleapis.com\".\n  string domain = 2;\n\n  // Additional structured details about this error.\n  //\n  // Keys must match a regular expression of `[a-z][a-zA-Z0-9-_]+` but should\n  // ideally be lowerCamelCase. Also, they must be limited to 64 characters in\n  // length. When identifying the current value of an exceeded limit, the units\n  // should be contained in the key, not the value.  For example, rather than\n  // `{\"instanceLimit\": \"100/request\"}`, should be returned as,\n  // `{\"instanceLimitPerRequest\": \"100\"}`, if the client exceeds the number of\n  // instances that can be created in a single (batch) request.\n  map<string, string> metadata = 3;\n}\n\n// Describes when the clients can retry a failed request. Clients could ignore\n// the recommendation here or retry when this information is missing from error\n// responses.\n//\n// It's always recommended that clients should use exponential backoff when\n// retrying.\n//\n// Clients should wait until `retry_delay` amount of time has passed since\n// receiving the error response before retrying.  If retrying requests also\n// fail, clients should use an exponential backoff scheme to gradually increase\n// the delay between retries based on `retry_delay`, until either a maximum\n// number of retries have been reached or a maximum retry delay cap has been\n// reached.\nmessage RetryInfo {\n  // Clients should wait at least this long between retrying the same request.\n  google.protobuf.Duration retry_delay = 1;\n}\n\n// Describes additional debugging info.\nmessage DebugInfo {\n  // The stack trace entries indicating where the error occurred.\n  repeated string stack_entries = 1;\n\n  // Additional debugging information provided by the server.\n  string detail = 2;\n}\n\n// Describes how a quota check failed.\n//\n// For example if a daily limit was exceeded for the calling project,\n// a service could respond with a QuotaFailure detail containing the project\n// id and the description of the quota limit that was exceeded.  If the\n// calling project hasn't enabled the service in the developer console, then\n// a service could respond with the project id and set `service_disabled`\n// to true.\n//\n// Also see RetryInfo and Help types for other details about handling a\n// quota failure.\nmessage QuotaFailure {\n  // A message type used to describe a single quota violation.  For example, a\n  // daily quota or a custom quota that was exceeded.\n  message Violation {\n    // The subject on which the quota check failed.\n    // For example, \"clientip:<ip address of client>\" or \"project:<Google\n    // developer project id>\".\n    string subject = 1;\n\n    // A description of how the quota check failed. Clients can use this\n    // description to find more about the quota configuration in the service's\n    // public documentation, or find the relevant quota limit to adjust through\n    // developer console.\n    //\n    // For example: \"Service disabled\" or \"Daily Limit for read operations\n    // exceeded\".\n    string description = 2;\n\n    // The API Service from which the `QuotaFailure.Violation` orginates. In\n    // some cases, Quota issues originate from an API Service other than the one\n    // that was called. In other words, a dependency of the called API Service\n    // could be the cause of the `QuotaFailure`, and this field would have the\n    // dependency API service name.\n    //\n    // For example, if the called API is Kubernetes Engine API\n    // (container.googleapis.com), and a quota violation occurs in the\n    // Kubernetes Engine API itself, this field would be\n    // \"container.googleapis.com\". On the other hand, if the quota violation\n    // occurs when the Kubernetes Engine API creates VMs in the Compute Engine\n    // API (compute.googleapis.com), this field would be\n    // \"compute.googleapis.com\".\n    string api_service = 3;\n\n    // The metric of the violated quota. A quota metric is a named counter to\n    // measure usage, such as API requests or CPUs. When an activity occurs in a\n    // service, such as Virtual Machine allocation, one or more quota metrics\n    // may be affected.\n    //\n    // For example, \"compute.googleapis.com/cpus_per_vm_family\",\n    // \"storage.googleapis.com/internet_egress_bandwidth\".\n    string quota_metric = 4;\n\n    // The id of the violated quota. Also know as \"limit name\", this is the\n    // unique identifier of a quota in the context of an API service.\n    //\n    // For example, \"CPUS-PER-VM-FAMILY-per-project-region\".\n    string quota_id = 5;\n\n    // The dimensions of the violated quota. Every non-global quota is enforced\n    // on a set of dimensions. While quota metric defines what to count, the\n    // dimensions specify for what aspects the counter should be increased.\n    //\n    // For example, the quota \"CPUs per region per VM family\" enforces a limit\n    // on the metric \"compute.googleapis.com/cpus_per_vm_family\" on dimensions\n    // \"region\" and \"vm_family\". And if the violation occurred in region\n    // \"us-central1\" and for VM family \"n1\", the quota_dimensions would be,\n    //\n    // {\n    //   \"region\": \"us-central1\",\n    //   \"vm_family\": \"n1\",\n    // }\n    //\n    // When a quota is enforced globally, the quota_dimensions would always be\n    // empty.\n    map<string, string> quota_dimensions = 6;\n\n    // The enforced quota value at the time of the `QuotaFailure`.\n    //\n    // For example, if the enforced quota value at the time of the\n    // `QuotaFailure` on the number of CPUs is \"10\", then the value of this\n    // field would reflect this quantity.\n    int64 quota_value = 7;\n\n    // The new quota value being rolled out at the time of the violation. At the\n    // completion of the rollout, this value will be enforced in place of\n    // quota_value. If no rollout is in progress at the time of the violation,\n    // this field is not set.\n    //\n    // For example, if at the time of the violation a rollout is in progress\n    // changing the number of CPUs quota from 10 to 20, 20 would be the value of\n    // this field.\n    optional int64 future_quota_value = 8;\n  }\n\n  // Describes all quota violations.\n  repeated Violation violations = 1;\n}\n\n// Describes what preconditions have failed.\n//\n// For example, if an RPC failed because it required the Terms of Service to be\n// acknowledged, it could list the terms of service violation in the\n// PreconditionFailure message.\nmessage PreconditionFailure {\n  // A message type used to describe a single precondition failure.\n  message Violation {\n    // The type of PreconditionFailure. We recommend using a service-specific\n    // enum type to define the supported precondition violation subjects. For\n    // example, \"TOS\" for \"Terms of Service violation\".\n    string type = 1;\n\n    // The subject, relative to the type, that failed.\n    // For example, \"google.com/cloud\" relative to the \"TOS\" type would indicate\n    // which terms of service is being referenced.\n    string subject = 2;\n\n    // A description of how the precondition failed. Developers can use this\n    // description to understand how to fix the failure.\n    //\n    // For example: \"Terms of service not accepted\".\n    string description = 3;\n  }\n\n  // Describes all precondition violations.\n  repeated Violation violations = 1;\n}\n\n// Describes violations in a client request. This error type focuses on the\n// syntactic aspects of the request.\nmessage BadRequest {\n  // A message type used to describe a single bad request field.\n  message FieldViolation {\n    // A path that leads to a field in the request body. The value will be a\n    // sequence of dot-separated identifiers that identify a protocol buffer\n    // field.\n    //\n    // Consider the following:\n    //\n    //     message CreateContactRequest {\n    //       message EmailAddress {\n    //         enum Type {\n    //           TYPE_UNSPECIFIED = 0;\n    //           HOME = 1;\n    //           WORK = 2;\n    //         }\n    //\n    //         optional string email = 1;\n    //         repeated EmailType type = 2;\n    //       }\n    //\n    //       string full_name = 1;\n    //       repeated EmailAddress email_addresses = 2;\n    //     }\n    //\n    // In this example, in proto `field` could take one of the following values:\n    //\n    // * `full_name` for a violation in the `full_name` value\n    // * `email_addresses[1].email` for a violation in the `email` field of the\n    //   first `email_addresses` message\n    // * `email_addresses[3].type[2]` for a violation in the second `type`\n    //   value in the third `email_addresses` message.\n    //\n    // In JSON, the same values are represented as:\n    //\n    // * `fullName` for a violation in the `fullName` value\n    // * `emailAddresses[1].email` for a violation in the `email` field of the\n    //   first `emailAddresses` message\n    // * `emailAddresses[3].type[2]` for a violation in the second `type`\n    //   value in the third `emailAddresses` message.\n    string field = 1;\n\n    // A description of why the request element is bad.\n    string description = 2;\n\n    // The reason of the field-level error. This is a constant value that\n    // identifies the proximate cause of the field-level error. It should\n    // uniquely identify the type of the FieldViolation within the scope of the\n    // google.rpc.ErrorInfo.domain. This should be at most 63\n    // characters and match a regular expression of `[A-Z][A-Z0-9_]+[A-Z0-9]`,\n    // which represents UPPER_SNAKE_CASE.\n    string reason = 3;\n\n    // Provides a localized error message for field-level errors that is safe to\n    // return to the API consumer.\n    LocalizedMessage localized_message = 4;\n  }\n\n  // Describes all violations in a client request.\n  repeated FieldViolation field_violations = 1;\n}\n\n// Contains metadata about the request that clients can attach when filing a bug\n// or providing other forms of feedback.\nmessage RequestInfo {\n  // An opaque string that should only be interpreted by the service generating\n  // it. For example, it can be used to identify requests in the service's logs.\n  string request_id = 1;\n\n  // Any data that was used to serve this request. For example, an encrypted\n  // stack trace that can be sent back to the service provider for debugging.\n  string serving_data = 2;\n}\n\n// Describes the resource that is being accessed.\nmessage ResourceInfo {\n  // A name for the type of resource being accessed, e.g. \"sql table\",\n  // \"cloud storage bucket\", \"file\", \"Google calendar\"; or the type URL\n  // of the resource: e.g. \"type.googleapis.com/google.pubsub.v1.Topic\".\n  string resource_type = 1;\n\n  // The name of the resource being accessed.  For example, a shared calendar\n  // name: \"example.com_4fghdhgsrgh@group.calendar.google.com\", if the current\n  // error is\n  // [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED].\n  string resource_name = 2;\n\n  // The owner of the resource (optional).\n  // For example, \"user:<owner email>\" or \"project:<Google developer project\n  // id>\".\n  string owner = 3;\n\n  // Describes what error is encountered when accessing this resource.\n  // For example, updating a cloud project may require the `writer` permission\n  // on the developer console project.\n  string description = 4;\n}\n\n// Provides links to documentation or for performing an out of band action.\n//\n// For example, if a quota check failed with an error indicating the calling\n// project hasn't enabled the accessed service, this can contain a URL pointing\n// directly to the right place in the developer console to flip the bit.\nmessage Help {\n  // Describes a URL link.\n  message Link {\n    // Describes what the link offers.\n    string description = 1;\n\n    // The URL of the link.\n    string url = 2;\n  }\n\n  // URL(s) pointing to additional information on handling the current error.\n  repeated Link links = 1;\n}\n\n// Provides a localized error message that is safe to return to the user\n// which can be attached to an RPC error.\nmessage LocalizedMessage {\n  // The locale used following the specification defined at\n  // https://www.rfc-editor.org/rfc/bcp/bcp47.txt.\n  // Examples are: \"en-US\", \"fr-CH\", \"es-MX\"\n  string locale = 1;\n\n  // The localized error message in the above locale.\n  string message = 2;\n}\n"
  },
  {
    "path": "tonic-types/proto/status.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.rpc;\n\nimport \"google/protobuf/any.proto\";\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/rpc/status;status\";\noption java_multiple_files = true;\noption java_outer_classname = \"StatusProto\";\noption java_package = \"com.google.rpc\";\noption objc_class_prefix = \"RPC\";\n\n// The `Status` type defines a logical error model that is suitable for\n// different programming environments, including REST APIs and RPC APIs. It is\n// used by [gRPC](https://github.com/grpc). Each `Status` message contains\n// three pieces of data: error code, error message, and error details.\n//\n// You can find out more about this error model and how to work with it in the\n// [API Design Guide](https://cloud.google.com/apis/design/errors).\nmessage Status {\n  // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].\n  int32 code = 1;\n\n  // A developer-facing error message, which should be in English. Any\n  // user-facing error message should be localized and sent in the\n  // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.\n  string message = 2;\n\n  // A list of messages that carry the error details.  There is a common set of\n  // message types for APIs to use.\n  repeated google.protobuf.Any details = 3;\n}\n"
  },
  {
    "path": "tonic-types/src/generated/google_rpc.rs",
    "content": "// This file is @generated by prost-build.\n/// The `Status` type defines a logical error model that is suitable for\n/// different programming environments, including REST APIs and RPC APIs. It is\n/// used by [gRPC](<https://github.com/grpc>). Each `Status` message contains\n/// three pieces of data: error code, error message, and error details.\n///\n/// You can find out more about this error model and how to work with it in the\n/// [API Design Guide](<https://cloud.google.com/apis/design/errors>).\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct Status {\n    /// The status code, which should be an enum value of \\[google.rpc.Code\\]\\[google.rpc.Code\\].\n    #[prost(int32, tag = \"1\")]\n    pub code: i32,\n    /// A developer-facing error message, which should be in English. Any\n    /// user-facing error message should be localized and sent in the\n    /// \\[google.rpc.Status.details\\]\\[google.rpc.Status.details\\] field, or localized by the client.\n    #[prost(string, tag = \"2\")]\n    pub message: ::prost::alloc::string::String,\n    /// A list of messages that carry the error details.  There is a common set of\n    /// message types for APIs to use.\n    #[prost(message, repeated, tag = \"3\")]\n    pub details: ::prost::alloc::vec::Vec<::prost_types::Any>,\n}\n/// Describes the cause of the error with structured details.\n///\n/// Example of an error when contacting the \"pubsub.googleapis.com\" API when it\n/// is not enabled:\n///\n/// ```text\n/// { \"reason\": \"API_DISABLED\"\n///    \"domain\": \"googleapis.com\"\n///    \"metadata\": {\n///      \"resource\": \"projects/123\",\n///      \"service\": \"pubsub.googleapis.com\"\n///    }\n/// }\n/// ```\n///\n/// This response indicates that the pubsub.googleapis.com API is not enabled.\n///\n/// Example of an error that is returned when attempting to create a Spanner\n/// instance in a region that is out of stock:\n///\n/// ```text\n/// { \"reason\": \"STOCKOUT\"\n///    \"domain\": \"spanner.googleapis.com\",\n///    \"metadata\": {\n///      \"availableRegions\": \"us-central1,us-east2\"\n///    }\n/// }\n/// ```\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct ErrorInfo {\n    /// The reason of the error. This is a constant value that identifies the\n    /// proximate cause of the error. Error reasons are unique within a particular\n    /// domain of errors. This should be at most 63 characters and match a\n    /// regular expression of `[A-Z][A-Z0-9_]+\\[A-Z0-9\\]`, which represents\n    /// UPPER_SNAKE_CASE.\n    #[prost(string, tag = \"1\")]\n    pub reason: ::prost::alloc::string::String,\n    /// The logical grouping to which the \"reason\" belongs. The error domain\n    /// is typically the registered service name of the tool or product that\n    /// generates the error. Example: \"pubsub.googleapis.com\". If the error is\n    /// generated by some common infrastructure, the error domain must be a\n    /// globally unique value that identifies the infrastructure. For Google API\n    /// infrastructure, the error domain is \"googleapis.com\".\n    #[prost(string, tag = \"2\")]\n    pub domain: ::prost::alloc::string::String,\n    /// Additional structured details about this error.\n    ///\n    /// Keys must match a regular expression of `[a-z][a-zA-Z0-9-_]+` but should\n    /// ideally be lowerCamelCase. Also, they must be limited to 64 characters in\n    /// length. When identifying the current value of an exceeded limit, the units\n    /// should be contained in the key, not the value.  For example, rather than\n    /// `{\"instanceLimit\": \"100/request\"}`, should be returned as,\n    /// `{\"instanceLimitPerRequest\": \"100\"}`, if the client exceeds the number of\n    /// instances that can be created in a single (batch) request.\n    #[prost(map = \"string, string\", tag = \"3\")]\n    pub metadata: ::std::collections::HashMap<\n        ::prost::alloc::string::String,\n        ::prost::alloc::string::String,\n    >,\n}\n/// Describes when the clients can retry a failed request. Clients could ignore\n/// the recommendation here or retry when this information is missing from error\n/// responses.\n///\n/// It's always recommended that clients should use exponential backoff when\n/// retrying.\n///\n/// Clients should wait until `retry_delay` amount of time has passed since\n/// receiving the error response before retrying.  If retrying requests also\n/// fail, clients should use an exponential backoff scheme to gradually increase\n/// the delay between retries based on `retry_delay`, until either a maximum\n/// number of retries have been reached or a maximum retry delay cap has been\n/// reached.\n#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]\npub struct RetryInfo {\n    /// Clients should wait at least this long between retrying the same request.\n    #[prost(message, optional, tag = \"1\")]\n    pub retry_delay: ::core::option::Option<::prost_types::Duration>,\n}\n/// Describes additional debugging info.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct DebugInfo {\n    /// The stack trace entries indicating where the error occurred.\n    #[prost(string, repeated, tag = \"1\")]\n    pub stack_entries: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,\n    /// Additional debugging information provided by the server.\n    #[prost(string, tag = \"2\")]\n    pub detail: ::prost::alloc::string::String,\n}\n/// Describes how a quota check failed.\n///\n/// For example if a daily limit was exceeded for the calling project,\n/// a service could respond with a QuotaFailure detail containing the project\n/// id and the description of the quota limit that was exceeded.  If the\n/// calling project hasn't enabled the service in the developer console, then\n/// a service could respond with the project id and set `service_disabled`\n/// to true.\n///\n/// Also see RetryInfo and Help types for other details about handling a\n/// quota failure.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct QuotaFailure {\n    /// Describes all quota violations.\n    #[prost(message, repeated, tag = \"1\")]\n    pub violations: ::prost::alloc::vec::Vec<quota_failure::Violation>,\n}\n/// Nested message and enum types in `QuotaFailure`.\npub mod quota_failure {\n    /// A message type used to describe a single quota violation.  For example, a\n    /// daily quota or a custom quota that was exceeded.\n    #[derive(Clone, PartialEq, ::prost::Message)]\n    pub struct Violation {\n        /// The subject on which the quota check failed.\n        /// For example, \"clientip:<ip address of client>\" or \"project:<Google\n        /// developer project id>\".\n        #[prost(string, tag = \"1\")]\n        pub subject: ::prost::alloc::string::String,\n        /// A description of how the quota check failed. Clients can use this\n        /// description to find more about the quota configuration in the service's\n        /// public documentation, or find the relevant quota limit to adjust through\n        /// developer console.\n        ///\n        /// For example: \"Service disabled\" or \"Daily Limit for read operations\n        /// exceeded\".\n        #[prost(string, tag = \"2\")]\n        pub description: ::prost::alloc::string::String,\n        /// The API Service from which the `QuotaFailure.Violation` orginates. In\n        /// some cases, Quota issues originate from an API Service other than the one\n        /// that was called. In other words, a dependency of the called API Service\n        /// could be the cause of the `QuotaFailure`, and this field would have the\n        /// dependency API service name.\n        ///\n        /// For example, if the called API is Kubernetes Engine API\n        /// (container.googleapis.com), and a quota violation occurs in the\n        /// Kubernetes Engine API itself, this field would be\n        /// \"container.googleapis.com\". On the other hand, if the quota violation\n        /// occurs when the Kubernetes Engine API creates VMs in the Compute Engine\n        /// API (compute.googleapis.com), this field would be\n        /// \"compute.googleapis.com\".\n        #[prost(string, tag = \"3\")]\n        pub api_service: ::prost::alloc::string::String,\n        /// The metric of the violated quota. A quota metric is a named counter to\n        /// measure usage, such as API requests or CPUs. When an activity occurs in a\n        /// service, such as Virtual Machine allocation, one or more quota metrics\n        /// may be affected.\n        ///\n        /// For example, \"compute.googleapis.com/cpus_per_vm_family\",\n        /// \"storage.googleapis.com/internet_egress_bandwidth\".\n        #[prost(string, tag = \"4\")]\n        pub quota_metric: ::prost::alloc::string::String,\n        /// The id of the violated quota. Also know as \"limit name\", this is the\n        /// unique identifier of a quota in the context of an API service.\n        ///\n        /// For example, \"CPUS-PER-VM-FAMILY-per-project-region\".\n        #[prost(string, tag = \"5\")]\n        pub quota_id: ::prost::alloc::string::String,\n        /// The dimensions of the violated quota. Every non-global quota is enforced\n        /// on a set of dimensions. While quota metric defines what to count, the\n        /// dimensions specify for what aspects the counter should be increased.\n        ///\n        /// For example, the quota \"CPUs per region per VM family\" enforces a limit\n        /// on the metric \"compute.googleapis.com/cpus_per_vm_family\" on dimensions\n        /// \"region\" and \"vm_family\". And if the violation occurred in region\n        /// \"us-central1\" and for VM family \"n1\", the quota_dimensions would be,\n        ///\n        /// {\n        /// \"region\": \"us-central1\",\n        /// \"vm_family\": \"n1\",\n        /// }\n        ///\n        /// When a quota is enforced globally, the quota_dimensions would always be\n        /// empty.\n        #[prost(map = \"string, string\", tag = \"6\")]\n        pub quota_dimensions: ::std::collections::HashMap<\n            ::prost::alloc::string::String,\n            ::prost::alloc::string::String,\n        >,\n        /// The enforced quota value at the time of the `QuotaFailure`.\n        ///\n        /// For example, if the enforced quota value at the time of the\n        /// `QuotaFailure` on the number of CPUs is \"10\", then the value of this\n        /// field would reflect this quantity.\n        #[prost(int64, tag = \"7\")]\n        pub quota_value: i64,\n        /// The new quota value being rolled out at the time of the violation. At the\n        /// completion of the rollout, this value will be enforced in place of\n        /// quota_value. If no rollout is in progress at the time of the violation,\n        /// this field is not set.\n        ///\n        /// For example, if at the time of the violation a rollout is in progress\n        /// changing the number of CPUs quota from 10 to 20, 20 would be the value of\n        /// this field.\n        #[prost(int64, optional, tag = \"8\")]\n        pub future_quota_value: ::core::option::Option<i64>,\n    }\n}\n/// Describes what preconditions have failed.\n///\n/// For example, if an RPC failed because it required the Terms of Service to be\n/// acknowledged, it could list the terms of service violation in the\n/// PreconditionFailure message.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct PreconditionFailure {\n    /// Describes all precondition violations.\n    #[prost(message, repeated, tag = \"1\")]\n    pub violations: ::prost::alloc::vec::Vec<precondition_failure::Violation>,\n}\n/// Nested message and enum types in `PreconditionFailure`.\npub mod precondition_failure {\n    /// A message type used to describe a single precondition failure.\n    #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\n    pub struct Violation {\n        /// The type of PreconditionFailure. We recommend using a service-specific\n        /// enum type to define the supported precondition violation subjects. For\n        /// example, \"TOS\" for \"Terms of Service violation\".\n        #[prost(string, tag = \"1\")]\n        pub r#type: ::prost::alloc::string::String,\n        /// The subject, relative to the type, that failed.\n        /// For example, \"google.com/cloud\" relative to the \"TOS\" type would indicate\n        /// which terms of service is being referenced.\n        #[prost(string, tag = \"2\")]\n        pub subject: ::prost::alloc::string::String,\n        /// A description of how the precondition failed. Developers can use this\n        /// description to understand how to fix the failure.\n        ///\n        /// For example: \"Terms of service not accepted\".\n        #[prost(string, tag = \"3\")]\n        pub description: ::prost::alloc::string::String,\n    }\n}\n/// Describes violations in a client request. This error type focuses on the\n/// syntactic aspects of the request.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct BadRequest {\n    /// Describes all violations in a client request.\n    #[prost(message, repeated, tag = \"1\")]\n    pub field_violations: ::prost::alloc::vec::Vec<bad_request::FieldViolation>,\n}\n/// Nested message and enum types in `BadRequest`.\npub mod bad_request {\n    /// A message type used to describe a single bad request field.\n    #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\n    pub struct FieldViolation {\n        /// A path that leads to a field in the request body. The value will be a\n        /// sequence of dot-separated identifiers that identify a protocol buffer\n        /// field.\n        ///\n        /// Consider the following:\n        ///\n        /// ```text\n        /// message CreateContactRequest {\n        ///    message EmailAddress {\n        ///      enum Type {\n        ///        TYPE_UNSPECIFIED = 0;\n        ///        HOME = 1;\n        ///        WORK = 2;\n        ///      }\n        ///\n        ///      optional string email = 1;\n        ///      repeated EmailType type = 2;\n        ///    }\n        ///\n        ///    string full_name = 1;\n        ///    repeated EmailAddress email_addresses = 2;\n        /// }\n        /// ```\n        ///\n        /// In this example, in proto `field` could take one of the following values:\n        ///\n        /// * `full_name` for a violation in the `full_name` value\n        /// * `email_addresses\\[1\\].email` for a violation in the `email` field of the\n        ///   first `email_addresses` message\n        /// * `email_addresses\\[3\\].type\\[2\\]` for a violation in the second `type`\n        ///   value in the third `email_addresses` message.\n        ///\n        /// In JSON, the same values are represented as:\n        ///\n        /// * `fullName` for a violation in the `fullName` value\n        /// * `emailAddresses\\[1\\].email` for a violation in the `email` field of the\n        ///   first `emailAddresses` message\n        /// * `emailAddresses\\[3\\].type\\[2\\]` for a violation in the second `type`\n        ///   value in the third `emailAddresses` message.\n        #[prost(string, tag = \"1\")]\n        pub field: ::prost::alloc::string::String,\n        /// A description of why the request element is bad.\n        #[prost(string, tag = \"2\")]\n        pub description: ::prost::alloc::string::String,\n        /// The reason of the field-level error. This is a constant value that\n        /// identifies the proximate cause of the field-level error. It should\n        /// uniquely identify the type of the FieldViolation within the scope of the\n        /// google.rpc.ErrorInfo.domain. This should be at most 63\n        /// characters and match a regular expression of `[A-Z][A-Z0-9_]+\\[A-Z0-9\\]`,\n        /// which represents UPPER_SNAKE_CASE.\n        #[prost(string, tag = \"3\")]\n        pub reason: ::prost::alloc::string::String,\n        /// Provides a localized error message for field-level errors that is safe to\n        /// return to the API consumer.\n        #[prost(message, optional, tag = \"4\")]\n        pub localized_message: ::core::option::Option<super::LocalizedMessage>,\n    }\n}\n/// Contains metadata about the request that clients can attach when filing a bug\n/// or providing other forms of feedback.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct RequestInfo {\n    /// An opaque string that should only be interpreted by the service generating\n    /// it. For example, it can be used to identify requests in the service's logs.\n    #[prost(string, tag = \"1\")]\n    pub request_id: ::prost::alloc::string::String,\n    /// Any data that was used to serve this request. For example, an encrypted\n    /// stack trace that can be sent back to the service provider for debugging.\n    #[prost(string, tag = \"2\")]\n    pub serving_data: ::prost::alloc::string::String,\n}\n/// Describes the resource that is being accessed.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct ResourceInfo {\n    /// A name for the type of resource being accessed, e.g. \"sql table\",\n    /// \"cloud storage bucket\", \"file\", \"Google calendar\"; or the type URL\n    /// of the resource: e.g. \"type.googleapis.com/google.pubsub.v1.Topic\".\n    #[prost(string, tag = \"1\")]\n    pub resource_type: ::prost::alloc::string::String,\n    /// The name of the resource being accessed.  For example, a shared calendar\n    /// name: \"example.com_4fghdhgsrgh@group.calendar.google.com\", if the current\n    /// error is\n    /// \\[google.rpc.Code.PERMISSION_DENIED\\]\\[google.rpc.Code.PERMISSION_DENIED\\].\n    #[prost(string, tag = \"2\")]\n    pub resource_name: ::prost::alloc::string::String,\n    /// The owner of the resource (optional).\n    /// For example, \"user:<owner email>\" or \"project:<Google developer project\n    /// id>\".\n    #[prost(string, tag = \"3\")]\n    pub owner: ::prost::alloc::string::String,\n    /// Describes what error is encountered when accessing this resource.\n    /// For example, updating a cloud project may require the `writer` permission\n    /// on the developer console project.\n    #[prost(string, tag = \"4\")]\n    pub description: ::prost::alloc::string::String,\n}\n/// Provides links to documentation or for performing an out of band action.\n///\n/// For example, if a quota check failed with an error indicating the calling\n/// project hasn't enabled the accessed service, this can contain a URL pointing\n/// directly to the right place in the developer console to flip the bit.\n#[derive(Clone, PartialEq, ::prost::Message)]\npub struct Help {\n    /// URL(s) pointing to additional information on handling the current error.\n    #[prost(message, repeated, tag = \"1\")]\n    pub links: ::prost::alloc::vec::Vec<help::Link>,\n}\n/// Nested message and enum types in `Help`.\npub mod help {\n    /// Describes a URL link.\n    #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\n    pub struct Link {\n        /// Describes what the link offers.\n        #[prost(string, tag = \"1\")]\n        pub description: ::prost::alloc::string::String,\n        /// The URL of the link.\n        #[prost(string, tag = \"2\")]\n        pub url: ::prost::alloc::string::String,\n    }\n}\n/// Provides a localized error message that is safe to return to the user\n/// which can be attached to an RPC error.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct LocalizedMessage {\n    /// The locale used following the specification defined at\n    /// <https://www.rfc-editor.org/rfc/bcp/bcp47.txt.>\n    /// Examples are: \"en-US\", \"fr-CH\", \"es-MX\"\n    #[prost(string, tag = \"1\")]\n    pub locale: ::prost::alloc::string::String,\n    /// The localized error message in the above locale.\n    #[prost(string, tag = \"2\")]\n    pub message: ::prost::alloc::string::String,\n}\n"
  },
  {
    "path": "tonic-types/src/generated/types_fds.rs",
    "content": "// This file is @generated by codegen.\n//  Copyright 2020 Google LLC\n// \n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n// \n//      http://www.apache.org/licenses/LICENSE-2.0\n// \n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n//  Copyright 2025 Google LLC\n// \n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use this file except in compliance with the License.\n//  You may obtain a copy of the License at\n// \n//      http://www.apache.org/licenses/LICENSE-2.0\n// \n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS,\n//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//  See the License for the specific language governing permissions and\n//  limitations under the License.\n// \n/// Byte encoded FILE_DESCRIPTOR_SET.\npub const FILE_DESCRIPTOR_SET: &[u8] = &[\n    10u8, 228u8, 1u8, 10u8, 25u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 47u8, 112u8,\n    114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 47u8, 97u8, 110u8, 121u8, 46u8,\n    112u8, 114u8, 111u8, 116u8, 111u8, 18u8, 15u8, 103u8, 111u8, 111u8, 103u8, 108u8,\n    101u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 34u8, 54u8, 10u8,\n    3u8, 65u8, 110u8, 121u8, 18u8, 25u8, 10u8, 8u8, 116u8, 121u8, 112u8, 101u8, 95u8,\n    117u8, 114u8, 108u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 7u8, 116u8, 121u8, 112u8,\n    101u8, 85u8, 114u8, 108u8, 18u8, 20u8, 10u8, 5u8, 118u8, 97u8, 108u8, 117u8, 101u8,\n    24u8, 2u8, 32u8, 1u8, 40u8, 12u8, 82u8, 5u8, 118u8, 97u8, 108u8, 117u8, 101u8, 66u8,\n    118u8, 10u8, 19u8, 99u8, 111u8, 109u8, 46u8, 103u8, 111u8, 111u8, 103u8, 108u8,\n    101u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 66u8, 8u8, 65u8,\n    110u8, 121u8, 80u8, 114u8, 111u8, 116u8, 111u8, 80u8, 1u8, 90u8, 44u8, 103u8, 111u8,\n    111u8, 103u8, 108u8, 101u8, 46u8, 103u8, 111u8, 108u8, 97u8, 110u8, 103u8, 46u8,\n    111u8, 114u8, 103u8, 47u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8,\n    47u8, 116u8, 121u8, 112u8, 101u8, 115u8, 47u8, 107u8, 110u8, 111u8, 119u8, 110u8,\n    47u8, 97u8, 110u8, 121u8, 112u8, 98u8, 162u8, 2u8, 3u8, 71u8, 80u8, 66u8, 170u8, 2u8,\n    30u8, 71u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 80u8, 114u8, 111u8, 116u8,\n    111u8, 98u8, 117u8, 102u8, 46u8, 87u8, 101u8, 108u8, 108u8, 75u8, 110u8, 111u8,\n    119u8, 110u8, 84u8, 121u8, 112u8, 101u8, 115u8, 98u8, 6u8, 112u8, 114u8, 111u8,\n    116u8, 111u8, 51u8, 10u8, 136u8, 2u8, 10u8, 12u8, 115u8, 116u8, 97u8, 116u8, 117u8,\n    115u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 18u8, 10u8, 103u8, 111u8, 111u8,\n    103u8, 108u8, 101u8, 46u8, 114u8, 112u8, 99u8, 26u8, 25u8, 103u8, 111u8, 111u8,\n    103u8, 108u8, 101u8, 47u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8,\n    47u8, 97u8, 110u8, 121u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 34u8, 102u8, 10u8,\n    6u8, 83u8, 116u8, 97u8, 116u8, 117u8, 115u8, 18u8, 18u8, 10u8, 4u8, 99u8, 111u8,\n    100u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 5u8, 82u8, 4u8, 99u8, 111u8, 100u8, 101u8,\n    18u8, 24u8, 10u8, 7u8, 109u8, 101u8, 115u8, 115u8, 97u8, 103u8, 101u8, 24u8, 2u8,\n    32u8, 1u8, 40u8, 9u8, 82u8, 7u8, 109u8, 101u8, 115u8, 115u8, 97u8, 103u8, 101u8,\n    18u8, 46u8, 10u8, 7u8, 100u8, 101u8, 116u8, 97u8, 105u8, 108u8, 115u8, 24u8, 3u8,\n    32u8, 3u8, 40u8, 11u8, 50u8, 20u8, 46u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8,\n    46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 46u8, 65u8, 110u8,\n    121u8, 82u8, 7u8, 100u8, 101u8, 116u8, 97u8, 105u8, 108u8, 115u8, 66u8, 97u8, 10u8,\n    14u8, 99u8, 111u8, 109u8, 46u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8,\n    114u8, 112u8, 99u8, 66u8, 11u8, 83u8, 116u8, 97u8, 116u8, 117u8, 115u8, 80u8, 114u8,\n    111u8, 116u8, 111u8, 80u8, 1u8, 90u8, 55u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8,\n    46u8, 103u8, 111u8, 108u8, 97u8, 110u8, 103u8, 46u8, 111u8, 114u8, 103u8, 47u8,\n    103u8, 101u8, 110u8, 112u8, 114u8, 111u8, 116u8, 111u8, 47u8, 103u8, 111u8, 111u8,\n    103u8, 108u8, 101u8, 97u8, 112u8, 105u8, 115u8, 47u8, 114u8, 112u8, 99u8, 47u8,\n    115u8, 116u8, 97u8, 116u8, 117u8, 115u8, 59u8, 115u8, 116u8, 97u8, 116u8, 117u8,\n    115u8, 248u8, 1u8, 1u8, 162u8, 2u8, 3u8, 82u8, 80u8, 67u8, 98u8, 6u8, 112u8, 114u8,\n    111u8, 116u8, 111u8, 51u8, 10u8, 251u8, 1u8, 10u8, 30u8, 103u8, 111u8, 111u8, 103u8,\n    108u8, 101u8, 47u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 47u8,\n    100u8, 117u8, 114u8, 97u8, 116u8, 105u8, 111u8, 110u8, 46u8, 112u8, 114u8, 111u8,\n    116u8, 111u8, 18u8, 15u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 112u8,\n    114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 34u8, 58u8, 10u8, 8u8, 68u8, 117u8,\n    114u8, 97u8, 116u8, 105u8, 111u8, 110u8, 18u8, 24u8, 10u8, 7u8, 115u8, 101u8, 99u8,\n    111u8, 110u8, 100u8, 115u8, 24u8, 1u8, 32u8, 1u8, 40u8, 3u8, 82u8, 7u8, 115u8, 101u8,\n    99u8, 111u8, 110u8, 100u8, 115u8, 18u8, 20u8, 10u8, 5u8, 110u8, 97u8, 110u8, 111u8,\n    115u8, 24u8, 2u8, 32u8, 1u8, 40u8, 5u8, 82u8, 5u8, 110u8, 97u8, 110u8, 111u8, 115u8,\n    66u8, 131u8, 1u8, 10u8, 19u8, 99u8, 111u8, 109u8, 46u8, 103u8, 111u8, 111u8, 103u8,\n    108u8, 101u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 66u8,\n    13u8, 68u8, 117u8, 114u8, 97u8, 116u8, 105u8, 111u8, 110u8, 80u8, 114u8, 111u8,\n    116u8, 111u8, 80u8, 1u8, 90u8, 49u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8,\n    103u8, 111u8, 108u8, 97u8, 110u8, 103u8, 46u8, 111u8, 114u8, 103u8, 47u8, 112u8,\n    114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 47u8, 116u8, 121u8, 112u8, 101u8,\n    115u8, 47u8, 107u8, 110u8, 111u8, 119u8, 110u8, 47u8, 100u8, 117u8, 114u8, 97u8,\n    116u8, 105u8, 111u8, 110u8, 112u8, 98u8, 248u8, 1u8, 1u8, 162u8, 2u8, 3u8, 71u8,\n    80u8, 66u8, 170u8, 2u8, 30u8, 71u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 80u8,\n    114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 46u8, 87u8, 101u8, 108u8, 108u8,\n    75u8, 110u8, 111u8, 119u8, 110u8, 84u8, 121u8, 112u8, 101u8, 115u8, 98u8, 6u8, 112u8,\n    114u8, 111u8, 116u8, 111u8, 51u8, 10u8, 129u8, 15u8, 10u8, 19u8, 101u8, 114u8, 114u8,\n    111u8, 114u8, 95u8, 100u8, 101u8, 116u8, 97u8, 105u8, 108u8, 115u8, 46u8, 112u8,\n    114u8, 111u8, 116u8, 111u8, 18u8, 10u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8,\n    46u8, 114u8, 112u8, 99u8, 26u8, 30u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 47u8,\n    112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8, 102u8, 47u8, 100u8, 117u8, 114u8,\n    97u8, 116u8, 105u8, 111u8, 110u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 34u8,\n    185u8, 1u8, 10u8, 9u8, 69u8, 114u8, 114u8, 111u8, 114u8, 73u8, 110u8, 102u8, 111u8,\n    18u8, 22u8, 10u8, 6u8, 114u8, 101u8, 97u8, 115u8, 111u8, 110u8, 24u8, 1u8, 32u8, 1u8,\n    40u8, 9u8, 82u8, 6u8, 114u8, 101u8, 97u8, 115u8, 111u8, 110u8, 18u8, 22u8, 10u8, 6u8,\n    100u8, 111u8, 109u8, 97u8, 105u8, 110u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 6u8,\n    100u8, 111u8, 109u8, 97u8, 105u8, 110u8, 18u8, 63u8, 10u8, 8u8, 109u8, 101u8, 116u8,\n    97u8, 100u8, 97u8, 116u8, 97u8, 24u8, 3u8, 32u8, 3u8, 40u8, 11u8, 50u8, 35u8, 46u8,\n    103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 114u8, 112u8, 99u8, 46u8, 69u8,\n    114u8, 114u8, 111u8, 114u8, 73u8, 110u8, 102u8, 111u8, 46u8, 77u8, 101u8, 116u8,\n    97u8, 100u8, 97u8, 116u8, 97u8, 69u8, 110u8, 116u8, 114u8, 121u8, 82u8, 8u8, 109u8,\n    101u8, 116u8, 97u8, 100u8, 97u8, 116u8, 97u8, 26u8, 59u8, 10u8, 13u8, 77u8, 101u8,\n    116u8, 97u8, 100u8, 97u8, 116u8, 97u8, 69u8, 110u8, 116u8, 114u8, 121u8, 18u8, 16u8,\n    10u8, 3u8, 107u8, 101u8, 121u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 3u8, 107u8,\n    101u8, 121u8, 18u8, 20u8, 10u8, 5u8, 118u8, 97u8, 108u8, 117u8, 101u8, 24u8, 2u8,\n    32u8, 1u8, 40u8, 9u8, 82u8, 5u8, 118u8, 97u8, 108u8, 117u8, 101u8, 58u8, 2u8, 56u8,\n    1u8, 34u8, 71u8, 10u8, 9u8, 82u8, 101u8, 116u8, 114u8, 121u8, 73u8, 110u8, 102u8,\n    111u8, 18u8, 58u8, 10u8, 11u8, 114u8, 101u8, 116u8, 114u8, 121u8, 95u8, 100u8, 101u8,\n    108u8, 97u8, 121u8, 24u8, 1u8, 32u8, 1u8, 40u8, 11u8, 50u8, 25u8, 46u8, 103u8, 111u8,\n    111u8, 103u8, 108u8, 101u8, 46u8, 112u8, 114u8, 111u8, 116u8, 111u8, 98u8, 117u8,\n    102u8, 46u8, 68u8, 117u8, 114u8, 97u8, 116u8, 105u8, 111u8, 110u8, 82u8, 10u8, 114u8,\n    101u8, 116u8, 114u8, 121u8, 68u8, 101u8, 108u8, 97u8, 121u8, 34u8, 72u8, 10u8, 9u8,\n    68u8, 101u8, 98u8, 117u8, 103u8, 73u8, 110u8, 102u8, 111u8, 18u8, 35u8, 10u8, 13u8,\n    115u8, 116u8, 97u8, 99u8, 107u8, 95u8, 101u8, 110u8, 116u8, 114u8, 105u8, 101u8,\n    115u8, 24u8, 1u8, 32u8, 3u8, 40u8, 9u8, 82u8, 12u8, 115u8, 116u8, 97u8, 99u8, 107u8,\n    69u8, 110u8, 116u8, 114u8, 105u8, 101u8, 115u8, 18u8, 22u8, 10u8, 6u8, 100u8, 101u8,\n    116u8, 97u8, 105u8, 108u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 6u8, 100u8, 101u8,\n    116u8, 97u8, 105u8, 108u8, 34u8, 142u8, 4u8, 10u8, 12u8, 81u8, 117u8, 111u8, 116u8,\n    97u8, 70u8, 97u8, 105u8, 108u8, 117u8, 114u8, 101u8, 18u8, 66u8, 10u8, 10u8, 118u8,\n    105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8, 110u8, 115u8, 24u8, 1u8, 32u8, 3u8,\n    40u8, 11u8, 50u8, 34u8, 46u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 114u8,\n    112u8, 99u8, 46u8, 81u8, 117u8, 111u8, 116u8, 97u8, 70u8, 97u8, 105u8, 108u8, 117u8,\n    114u8, 101u8, 46u8, 86u8, 105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8, 110u8,\n    82u8, 10u8, 118u8, 105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8, 110u8, 115u8,\n    26u8, 185u8, 3u8, 10u8, 9u8, 86u8, 105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8,\n    110u8, 18u8, 24u8, 10u8, 7u8, 115u8, 117u8, 98u8, 106u8, 101u8, 99u8, 116u8, 24u8,\n    1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 7u8, 115u8, 117u8, 98u8, 106u8, 101u8, 99u8, 116u8,\n    18u8, 32u8, 10u8, 11u8, 100u8, 101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 105u8,\n    111u8, 110u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 11u8, 100u8, 101u8, 115u8, 99u8,\n    114u8, 105u8, 112u8, 116u8, 105u8, 111u8, 110u8, 18u8, 31u8, 10u8, 11u8, 97u8, 112u8,\n    105u8, 95u8, 115u8, 101u8, 114u8, 118u8, 105u8, 99u8, 101u8, 24u8, 3u8, 32u8, 1u8,\n    40u8, 9u8, 82u8, 10u8, 97u8, 112u8, 105u8, 83u8, 101u8, 114u8, 118u8, 105u8, 99u8,\n    101u8, 18u8, 33u8, 10u8, 12u8, 113u8, 117u8, 111u8, 116u8, 97u8, 95u8, 109u8, 101u8,\n    116u8, 114u8, 105u8, 99u8, 24u8, 4u8, 32u8, 1u8, 40u8, 9u8, 82u8, 11u8, 113u8, 117u8,\n    111u8, 116u8, 97u8, 77u8, 101u8, 116u8, 114u8, 105u8, 99u8, 18u8, 25u8, 10u8, 8u8,\n    113u8, 117u8, 111u8, 116u8, 97u8, 95u8, 105u8, 100u8, 24u8, 5u8, 32u8, 1u8, 40u8,\n    9u8, 82u8, 7u8, 113u8, 117u8, 111u8, 116u8, 97u8, 73u8, 100u8, 18u8, 98u8, 10u8,\n    16u8, 113u8, 117u8, 111u8, 116u8, 97u8, 95u8, 100u8, 105u8, 109u8, 101u8, 110u8,\n    115u8, 105u8, 111u8, 110u8, 115u8, 24u8, 6u8, 32u8, 3u8, 40u8, 11u8, 50u8, 55u8,\n    46u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 114u8, 112u8, 99u8, 46u8, 81u8,\n    117u8, 111u8, 116u8, 97u8, 70u8, 97u8, 105u8, 108u8, 117u8, 114u8, 101u8, 46u8, 86u8,\n    105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8, 110u8, 46u8, 81u8, 117u8, 111u8,\n    116u8, 97u8, 68u8, 105u8, 109u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 115u8,\n    69u8, 110u8, 116u8, 114u8, 121u8, 82u8, 15u8, 113u8, 117u8, 111u8, 116u8, 97u8, 68u8,\n    105u8, 109u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 115u8, 18u8, 31u8, 10u8,\n    11u8, 113u8, 117u8, 111u8, 116u8, 97u8, 95u8, 118u8, 97u8, 108u8, 117u8, 101u8, 24u8,\n    7u8, 32u8, 1u8, 40u8, 3u8, 82u8, 10u8, 113u8, 117u8, 111u8, 116u8, 97u8, 86u8, 97u8,\n    108u8, 117u8, 101u8, 18u8, 49u8, 10u8, 18u8, 102u8, 117u8, 116u8, 117u8, 114u8,\n    101u8, 95u8, 113u8, 117u8, 111u8, 116u8, 97u8, 95u8, 118u8, 97u8, 108u8, 117u8,\n    101u8, 24u8, 8u8, 32u8, 1u8, 40u8, 3u8, 72u8, 0u8, 82u8, 16u8, 102u8, 117u8, 116u8,\n    117u8, 114u8, 101u8, 81u8, 117u8, 111u8, 116u8, 97u8, 86u8, 97u8, 108u8, 117u8,\n    101u8, 136u8, 1u8, 1u8, 26u8, 66u8, 10u8, 20u8, 81u8, 117u8, 111u8, 116u8, 97u8,\n    68u8, 105u8, 109u8, 101u8, 110u8, 115u8, 105u8, 111u8, 110u8, 115u8, 69u8, 110u8,\n    116u8, 114u8, 121u8, 18u8, 16u8, 10u8, 3u8, 107u8, 101u8, 121u8, 24u8, 1u8, 32u8,\n    1u8, 40u8, 9u8, 82u8, 3u8, 107u8, 101u8, 121u8, 18u8, 20u8, 10u8, 5u8, 118u8, 97u8,\n    108u8, 117u8, 101u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 5u8, 118u8, 97u8, 108u8,\n    117u8, 101u8, 58u8, 2u8, 56u8, 1u8, 66u8, 21u8, 10u8, 19u8, 95u8, 102u8, 117u8,\n    116u8, 117u8, 114u8, 101u8, 95u8, 113u8, 117u8, 111u8, 116u8, 97u8, 95u8, 118u8,\n    97u8, 108u8, 117u8, 101u8, 34u8, 189u8, 1u8, 10u8, 19u8, 80u8, 114u8, 101u8, 99u8,\n    111u8, 110u8, 100u8, 105u8, 116u8, 105u8, 111u8, 110u8, 70u8, 97u8, 105u8, 108u8,\n    117u8, 114u8, 101u8, 18u8, 73u8, 10u8, 10u8, 118u8, 105u8, 111u8, 108u8, 97u8, 116u8,\n    105u8, 111u8, 110u8, 115u8, 24u8, 1u8, 32u8, 3u8, 40u8, 11u8, 50u8, 41u8, 46u8,\n    103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 114u8, 112u8, 99u8, 46u8, 80u8,\n    114u8, 101u8, 99u8, 111u8, 110u8, 100u8, 105u8, 116u8, 105u8, 111u8, 110u8, 70u8,\n    97u8, 105u8, 108u8, 117u8, 114u8, 101u8, 46u8, 86u8, 105u8, 111u8, 108u8, 97u8,\n    116u8, 105u8, 111u8, 110u8, 82u8, 10u8, 118u8, 105u8, 111u8, 108u8, 97u8, 116u8,\n    105u8, 111u8, 110u8, 115u8, 26u8, 91u8, 10u8, 9u8, 86u8, 105u8, 111u8, 108u8, 97u8,\n    116u8, 105u8, 111u8, 110u8, 18u8, 18u8, 10u8, 4u8, 116u8, 121u8, 112u8, 101u8, 24u8,\n    1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 4u8, 116u8, 121u8, 112u8, 101u8, 18u8, 24u8, 10u8,\n    7u8, 115u8, 117u8, 98u8, 106u8, 101u8, 99u8, 116u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8,\n    82u8, 7u8, 115u8, 117u8, 98u8, 106u8, 101u8, 99u8, 116u8, 18u8, 32u8, 10u8, 11u8,\n    100u8, 101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 105u8, 111u8, 110u8, 24u8,\n    3u8, 32u8, 1u8, 40u8, 9u8, 82u8, 11u8, 100u8, 101u8, 115u8, 99u8, 114u8, 105u8,\n    112u8, 116u8, 105u8, 111u8, 110u8, 34u8, 140u8, 2u8, 10u8, 10u8, 66u8, 97u8, 100u8,\n    82u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 18u8, 80u8, 10u8, 16u8, 102u8, 105u8,\n    101u8, 108u8, 100u8, 95u8, 118u8, 105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8,\n    110u8, 115u8, 24u8, 1u8, 32u8, 3u8, 40u8, 11u8, 50u8, 37u8, 46u8, 103u8, 111u8,\n    111u8, 103u8, 108u8, 101u8, 46u8, 114u8, 112u8, 99u8, 46u8, 66u8, 97u8, 100u8, 82u8,\n    101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 46u8, 70u8, 105u8, 101u8, 108u8, 100u8,\n    86u8, 105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8, 110u8, 82u8, 15u8, 102u8,\n    105u8, 101u8, 108u8, 100u8, 86u8, 105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8,\n    110u8, 115u8, 26u8, 171u8, 1u8, 10u8, 14u8, 70u8, 105u8, 101u8, 108u8, 100u8, 86u8,\n    105u8, 111u8, 108u8, 97u8, 116u8, 105u8, 111u8, 110u8, 18u8, 20u8, 10u8, 5u8, 102u8,\n    105u8, 101u8, 108u8, 100u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 5u8, 102u8, 105u8,\n    101u8, 108u8, 100u8, 18u8, 32u8, 10u8, 11u8, 100u8, 101u8, 115u8, 99u8, 114u8, 105u8,\n    112u8, 116u8, 105u8, 111u8, 110u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 11u8,\n    100u8, 101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 105u8, 111u8, 110u8, 18u8,\n    22u8, 10u8, 6u8, 114u8, 101u8, 97u8, 115u8, 111u8, 110u8, 24u8, 3u8, 32u8, 1u8, 40u8,\n    9u8, 82u8, 6u8, 114u8, 101u8, 97u8, 115u8, 111u8, 110u8, 18u8, 73u8, 10u8, 17u8,\n    108u8, 111u8, 99u8, 97u8, 108u8, 105u8, 122u8, 101u8, 100u8, 95u8, 109u8, 101u8,\n    115u8, 115u8, 97u8, 103u8, 101u8, 24u8, 4u8, 32u8, 1u8, 40u8, 11u8, 50u8, 28u8, 46u8,\n    103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 114u8, 112u8, 99u8, 46u8, 76u8,\n    111u8, 99u8, 97u8, 108u8, 105u8, 122u8, 101u8, 100u8, 77u8, 101u8, 115u8, 115u8,\n    97u8, 103u8, 101u8, 82u8, 16u8, 108u8, 111u8, 99u8, 97u8, 108u8, 105u8, 122u8, 101u8,\n    100u8, 77u8, 101u8, 115u8, 115u8, 97u8, 103u8, 101u8, 34u8, 79u8, 10u8, 11u8, 82u8,\n    101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 73u8, 110u8, 102u8, 111u8, 18u8, 29u8,\n    10u8, 10u8, 114u8, 101u8, 113u8, 117u8, 101u8, 115u8, 116u8, 95u8, 105u8, 100u8,\n    24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 9u8, 114u8, 101u8, 113u8, 117u8, 101u8, 115u8,\n    116u8, 73u8, 100u8, 18u8, 33u8, 10u8, 12u8, 115u8, 101u8, 114u8, 118u8, 105u8, 110u8,\n    103u8, 95u8, 100u8, 97u8, 116u8, 97u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 11u8,\n    115u8, 101u8, 114u8, 118u8, 105u8, 110u8, 103u8, 68u8, 97u8, 116u8, 97u8, 34u8,\n    144u8, 1u8, 10u8, 12u8, 82u8, 101u8, 115u8, 111u8, 117u8, 114u8, 99u8, 101u8, 73u8,\n    110u8, 102u8, 111u8, 18u8, 35u8, 10u8, 13u8, 114u8, 101u8, 115u8, 111u8, 117u8,\n    114u8, 99u8, 101u8, 95u8, 116u8, 121u8, 112u8, 101u8, 24u8, 1u8, 32u8, 1u8, 40u8,\n    9u8, 82u8, 12u8, 114u8, 101u8, 115u8, 111u8, 117u8, 114u8, 99u8, 101u8, 84u8, 121u8,\n    112u8, 101u8, 18u8, 35u8, 10u8, 13u8, 114u8, 101u8, 115u8, 111u8, 117u8, 114u8, 99u8,\n    101u8, 95u8, 110u8, 97u8, 109u8, 101u8, 24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 12u8,\n    114u8, 101u8, 115u8, 111u8, 117u8, 114u8, 99u8, 101u8, 78u8, 97u8, 109u8, 101u8,\n    18u8, 20u8, 10u8, 5u8, 111u8, 119u8, 110u8, 101u8, 114u8, 24u8, 3u8, 32u8, 1u8, 40u8,\n    9u8, 82u8, 5u8, 111u8, 119u8, 110u8, 101u8, 114u8, 18u8, 32u8, 10u8, 11u8, 100u8,\n    101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 105u8, 111u8, 110u8, 24u8, 4u8, 32u8,\n    1u8, 40u8, 9u8, 82u8, 11u8, 100u8, 101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8,\n    105u8, 111u8, 110u8, 34u8, 111u8, 10u8, 4u8, 72u8, 101u8, 108u8, 112u8, 18u8, 43u8,\n    10u8, 5u8, 108u8, 105u8, 110u8, 107u8, 115u8, 24u8, 1u8, 32u8, 3u8, 40u8, 11u8, 50u8,\n    21u8, 46u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 114u8, 112u8, 99u8, 46u8,\n    72u8, 101u8, 108u8, 112u8, 46u8, 76u8, 105u8, 110u8, 107u8, 82u8, 5u8, 108u8, 105u8,\n    110u8, 107u8, 115u8, 26u8, 58u8, 10u8, 4u8, 76u8, 105u8, 110u8, 107u8, 18u8, 32u8,\n    10u8, 11u8, 100u8, 101u8, 115u8, 99u8, 114u8, 105u8, 112u8, 116u8, 105u8, 111u8,\n    110u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 11u8, 100u8, 101u8, 115u8, 99u8, 114u8,\n    105u8, 112u8, 116u8, 105u8, 111u8, 110u8, 18u8, 16u8, 10u8, 3u8, 117u8, 114u8, 108u8,\n    24u8, 2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 3u8, 117u8, 114u8, 108u8, 34u8, 68u8, 10u8,\n    16u8, 76u8, 111u8, 99u8, 97u8, 108u8, 105u8, 122u8, 101u8, 100u8, 77u8, 101u8, 115u8,\n    115u8, 97u8, 103u8, 101u8, 18u8, 22u8, 10u8, 6u8, 108u8, 111u8, 99u8, 97u8, 108u8,\n    101u8, 24u8, 1u8, 32u8, 1u8, 40u8, 9u8, 82u8, 6u8, 108u8, 111u8, 99u8, 97u8, 108u8,\n    101u8, 18u8, 24u8, 10u8, 7u8, 109u8, 101u8, 115u8, 115u8, 97u8, 103u8, 101u8, 24u8,\n    2u8, 32u8, 1u8, 40u8, 9u8, 82u8, 7u8, 109u8, 101u8, 115u8, 115u8, 97u8, 103u8, 101u8,\n    66u8, 108u8, 10u8, 14u8, 99u8, 111u8, 109u8, 46u8, 103u8, 111u8, 111u8, 103u8, 108u8,\n    101u8, 46u8, 114u8, 112u8, 99u8, 66u8, 17u8, 69u8, 114u8, 114u8, 111u8, 114u8, 68u8,\n    101u8, 116u8, 97u8, 105u8, 108u8, 115u8, 80u8, 114u8, 111u8, 116u8, 111u8, 80u8, 1u8,\n    90u8, 63u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 46u8, 103u8, 111u8, 108u8,\n    97u8, 110u8, 103u8, 46u8, 111u8, 114u8, 103u8, 47u8, 103u8, 101u8, 110u8, 112u8,\n    114u8, 111u8, 116u8, 111u8, 47u8, 103u8, 111u8, 111u8, 103u8, 108u8, 101u8, 97u8,\n    112u8, 105u8, 115u8, 47u8, 114u8, 112u8, 99u8, 47u8, 101u8, 114u8, 114u8, 100u8,\n    101u8, 116u8, 97u8, 105u8, 108u8, 115u8, 59u8, 101u8, 114u8, 114u8, 100u8, 101u8,\n    116u8, 97u8, 105u8, 108u8, 115u8, 162u8, 2u8, 3u8, 82u8, 80u8, 67u8, 98u8, 6u8,\n    112u8, 114u8, 111u8, 116u8, 111u8, 51u8,\n];\n"
  },
  {
    "path": "tonic-types/src/lib.rs",
    "content": "//! A collection of useful protobuf types that can be used with `tonic`.\n//!\n//! This crate also introduces the [`StatusExt`] trait and implements it in\n//! [`tonic::Status`], allowing the implementation of the\n//! [gRPC Richer Error Model] with [`tonic`] in a convenient way.\n//!\n//! # Usage\n//!\n//! Useful protobuf types are available through the [`pb`] module. They can be\n//! imported and worked with directly.\n//!\n//! The [`StatusExt`] trait adds associated functions to [`tonic::Status`] that\n//! can be used on the server side to create a status with error details, which\n//! can then be returned to gRPC clients. Moreover, the trait also adds methods\n//! to [`tonic::Status`] that can be used by a tonic client to extract error\n//! details, and handle them with ease.\n//!\n//! # Getting Started\n//!\n//! ```toml\n//! [dependencies]\n//! tonic = <tonic-version>\n//! tonic-types = <tonic-types-version>\n//! ```\n//!\n//! # Examples\n//!\n//! The examples below cover a basic use case of the [gRPC Richer Error Model].\n//! More complete server and client implementations are provided in the\n//! **Richer Error example**, located in the main repo [examples] directory.\n//!\n//! ## Server Side: Generating [`tonic::Status`] with an [`ErrorDetails`] struct\n//!\n//! ```\n//! use tonic::{Code, Status};\n//! use tonic_types::{ErrorDetails, StatusExt};\n//!\n//! # async fn endpoint() -> Result<tonic::Response<()>, Status> {\n//! // ...\n//! // Inside a gRPC server endpoint that returns `Result<Response<T>, Status>`\n//!\n//! // Create empty `ErrorDetails` struct\n//! let mut err_details = ErrorDetails::new();\n//!\n//! // Add error details conditionally\n//! # let some_condition = true;\n//! if some_condition {\n//!     err_details.add_bad_request_violation(\n//!         \"field_a\",\n//!         \"description of why the field_a is invalid\"\n//!     );\n//! }\n//!\n//! # let other_condition = true;\n//! if other_condition {\n//!     err_details.add_bad_request_violation(\n//!         \"field_b\",\n//!         \"description of why the field_b is invalid\",\n//!     );\n//! }\n//!\n//! // Check if any error details were set and return error status if so\n//! if err_details.has_bad_request_violations() {\n//!     // Add additional error details if necessary\n//!     err_details\n//!         .add_help_link(\"description of link\", \"https://resource.example.local\")\n//!         .set_localized_message(\"en-US\", \"message for the user\");\n//!\n//!     let status = Status::with_error_details(\n//!         Code::InvalidArgument,\n//!         \"bad request\",\n//!         err_details,\n//!     );\n//!     return Err(status);\n//! }\n//!\n//! // Handle valid request\n//! // ...\n//! # Ok(tonic::Response::new(()))\n//! # }\n//! ```\n//!\n//! ## Client Side: Extracting an [`ErrorDetails`] struct from `tonic::Status`\n//!\n//! ```\n//! use tonic::{Response, Status};\n//! use tonic_types::StatusExt;\n//!\n//! // ...\n//! // Where `req_result` was returned by a gRPC client endpoint method\n//! fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n//!     match req_result {\n//!         Ok(response) => {\n//!             // Handle successful response\n//!         },\n//!         Err(status) => {\n//!             let err_details = status.get_error_details();\n//!             if let Some(bad_request) = err_details.bad_request() {\n//!                 // Handle bad_request details\n//!             }\n//!             if let Some(help) = err_details.help() {\n//!                 // Handle help details\n//!             }\n//!             if let Some(localized_message) = err_details.localized_message() {\n//!                 // Handle localized_message details\n//!             }\n//!         }\n//!     };\n//! }\n//! ```\n//!\n//! # Working with different error message types\n//!\n//! Multiple examples are provided at the [`ErrorDetails`] doc. Instructions\n//! about how to use the fields of the standard error message types correctly\n//! are provided at [error_details.proto].\n//!\n//! # Alternative `tonic::Status` associated functions and methods\n//!\n//! In the [`StatusExt`] doc, an alternative way of interacting with\n//! [`tonic::Status`] is presented, using vectors of error details structs\n//! wrapped with the [`ErrorDetail`] enum. This approach can provide more\n//! control over the vector of standard error messages that will be generated or\n//! that was received, if necessary. To see how to adopt this approach, please\n//! check the [`StatusExt::with_error_details_vec`] and\n//! [`StatusExt::get_error_details_vec`] docs, and also the main repo's\n//! [Richer Error example] directory.\n//!\n//! Besides that, multiple examples with alternative error details extraction\n//! methods are provided in the [`StatusExt`] doc, which can be specially\n//! useful if only one type of standard error message is being handled by the\n//! client. For example, using [`StatusExt::get_details_bad_request`] is a\n//! more direct way of extracting a [`BadRequest`] error message from\n//! [`tonic::Status`].\n//!\n//! [`tonic::Status`]: https://docs.rs/tonic/latest/tonic/struct.Status.html\n//! [`tonic`]: https://docs.rs/tonic/latest/tonic/\n//! [gRPC Richer Error Model]: https://www.grpc.io/docs/guides/error/\n//! [examples]: https://github.com/hyperium/tonic/tree/master/examples\n//! [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n//! [Richer Error example]: https://github.com/hyperium/tonic/tree/master/examples/src/richer-error\n\n#![doc(\n    html_logo_url = \"https://raw.githubusercontent.com/tokio-rs/website/master/public/img/icons/tonic.svg\"\n)]\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n\nmod generated {\n    #![allow(unreachable_pub)]\n    #![allow(rustdoc::invalid_html_tags)]\n    #[rustfmt::skip]\n    pub mod google_rpc;\n    #[rustfmt::skip]\n    pub mod types_fds;\n\n    pub use types_fds::FILE_DESCRIPTOR_SET;\n\n    #[cfg(test)]\n    mod tests {\n        use super::FILE_DESCRIPTOR_SET;\n        use prost::Message as _;\n\n        #[test]\n        fn file_descriptor_set_is_valid() {\n            prost_types::FileDescriptorSet::decode(FILE_DESCRIPTOR_SET).unwrap();\n        }\n    }\n}\n\n/// Useful protobuf types\npub mod pb {\n    pub use crate::generated::{FILE_DESCRIPTOR_SET, google_rpc::*};\n}\n\npub use pb::Status;\n\nmod richer_error;\n\npub use richer_error::{\n    BadRequest, DebugInfo, ErrorDetail, ErrorDetails, ErrorInfo, FieldViolation, Help, HelpLink,\n    LocalizedMessage, PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation,\n    RequestInfo, ResourceInfo, RetryInfo, RpcStatusExt, StatusExt,\n};\n\nmod sealed {\n    pub trait Sealed {}\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/error_details/mod.rs",
    "content": "use std::{collections::HashMap, time};\n\nuse super::std_messages::{\n    BadRequest, DebugInfo, ErrorInfo, FieldViolation, Help, HelpLink, LocalizedMessage,\n    PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation, RequestInfo,\n    ResourceInfo, RetryInfo,\n};\n\npub(crate) mod vec;\n\n/// Groups the standard error messages structs. Provides associated\n/// functions and methods to setup and edit each error message independently.\n/// Used when extracting error details from `tonic::Status`, and when\n/// creating a `tonic::Status` with error details.\n#[non_exhaustive]\n#[derive(Clone, Debug, Default)]\npub struct ErrorDetails {\n    /// This field stores [`RetryInfo`] data, if any.\n    pub(crate) retry_info: Option<RetryInfo>,\n\n    /// This field stores [`DebugInfo`] data, if any.\n    pub(crate) debug_info: Option<DebugInfo>,\n\n    /// This field stores [`QuotaFailure`] data, if any.\n    pub(crate) quota_failure: Option<QuotaFailure>,\n\n    /// This field stores [`ErrorInfo`] data, if any.\n    pub(crate) error_info: Option<ErrorInfo>,\n\n    /// This field stores [`PreconditionFailure`] data, if any.\n    pub(crate) precondition_failure: Option<PreconditionFailure>,\n\n    /// This field stores [`BadRequest`] data, if any.\n    pub(crate) bad_request: Option<BadRequest>,\n\n    /// This field stores [`RequestInfo`] data, if any.\n    pub(crate) request_info: Option<RequestInfo>,\n\n    /// This field stores [`ResourceInfo`] data, if any.\n    pub(crate) resource_info: Option<ResourceInfo>,\n\n    /// This field stores [`Help`] data, if any.\n    pub(crate) help: Option<Help>,\n\n    /// This field stores [`LocalizedMessage`] data, if any.\n    pub(crate) localized_message: Option<LocalizedMessage>,\n}\n\nimpl ErrorDetails {\n    /// Generates an [`ErrorDetails`] struct with all fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::new();\n    /// ```\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`RetryInfo`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use std::time::Duration;\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_retry_info(Some(Duration::from_secs(5)));\n    /// ```\n    pub fn with_retry_info(retry_delay: Option<time::Duration>) -> Self {\n        ErrorDetails {\n            retry_info: Some(RetryInfo::new(retry_delay)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`DebugInfo`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_stack = vec![\"...\".into(), \"...\".into()];\n    ///\n    /// let err_details = ErrorDetails::with_debug_info(err_stack, \"error details\");\n    /// ```\n    pub fn with_debug_info(\n        stack_entries: impl Into<Vec<String>>,\n        detail: impl Into<String>,\n    ) -> Self {\n        ErrorDetails {\n            debug_info: Some(DebugInfo::new(stack_entries, detail)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`QuotaFailure`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, QuotaViolation};\n    ///\n    /// let err_details = ErrorDetails::with_quota_failure(vec![\n    ///     QuotaViolation::new(\"subject 1\", \"description 1\"),\n    ///     QuotaViolation::new(\"subject 2\", \"description 2\"),\n    /// ]);\n    /// ```\n    pub fn with_quota_failure(violations: impl Into<Vec<QuotaViolation>>) -> Self {\n        ErrorDetails {\n            quota_failure: Some(QuotaFailure::new(violations)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`QuotaFailure`] details (one\n    /// [`QuotaViolation`] set) and remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_quota_failure_violation(\"subject\", \"description\");\n    /// ```\n    pub fn with_quota_failure_violation(\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> Self {\n        ErrorDetails {\n            quota_failure: Some(QuotaFailure::with_violation(subject, description)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`ErrorInfo`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use std::collections::HashMap;\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut metadata: HashMap<String, String> = HashMap::new();\n    /// metadata.insert(\"instanceLimitPerRequest\".into(), \"100\".into());\n    ///\n    /// let err_details = ErrorDetails::with_error_info(\"reason\", \"domain\", metadata);\n    /// ```\n    pub fn with_error_info(\n        reason: impl Into<String>,\n        domain: impl Into<String>,\n        metadata: impl Into<HashMap<String, String>>,\n    ) -> Self {\n        ErrorDetails {\n            error_info: Some(ErrorInfo::new(reason, domain, metadata)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`PreconditionFailure`]\n    /// details and remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, PreconditionViolation};\n    ///\n    /// let err_details = ErrorDetails::with_precondition_failure(vec![\n    ///     PreconditionViolation::new(\n    ///         \"violation type 1\",\n    ///         \"subject 1\",\n    ///         \"description 1\",\n    ///     ),\n    ///     PreconditionViolation::new(\n    ///         \"violation type 2\",\n    ///         \"subject 2\",\n    ///         \"description 2\",\n    ///     ),\n    /// ]);\n    /// ```\n    pub fn with_precondition_failure(violations: impl Into<Vec<PreconditionViolation>>) -> Self {\n        ErrorDetails {\n            precondition_failure: Some(PreconditionFailure::new(violations)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`PreconditionFailure`]\n    /// details (one [`PreconditionViolation`] set) and remaining fields set to\n    /// `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_precondition_failure_violation(\n    ///     \"violation type\",\n    ///     \"subject\",\n    ///     \"description\",\n    /// );\n    /// ```\n    pub fn with_precondition_failure_violation(\n        violation_type: impl Into<String>,\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> Self {\n        ErrorDetails {\n            precondition_failure: Some(PreconditionFailure::with_violation(\n                violation_type,\n                subject,\n                description,\n            )),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`BadRequest`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, FieldViolation};\n    ///\n    /// let err_details = ErrorDetails::with_bad_request(vec![\n    ///     FieldViolation::new(\"field_1\", \"description 1\"),\n    ///     FieldViolation::new(\"field_2\", \"description 2\"),\n    /// ]);\n    /// ```\n    pub fn with_bad_request(field_violations: impl Into<Vec<FieldViolation>>) -> Self {\n        ErrorDetails {\n            bad_request: Some(BadRequest::new(field_violations)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`BadRequest`] details (one\n    /// [`FieldViolation`] set) and remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_bad_request_violation(\n    ///     \"field\",\n    ///     \"description\",\n    /// );\n    /// ```\n    pub fn with_bad_request_violation(\n        field: impl Into<String>,\n        description: impl Into<String>,\n    ) -> Self {\n        ErrorDetails {\n            bad_request: Some(BadRequest::with_violation(field, description)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`RequestInfo`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_request_info(\n    ///     \"request_id\",\n    ///     \"serving_data\",\n    /// );\n    /// ```\n    pub fn with_request_info(\n        request_id: impl Into<String>,\n        serving_data: impl Into<String>,\n    ) -> Self {\n        ErrorDetails {\n            request_info: Some(RequestInfo::new(request_id, serving_data)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`ResourceInfo`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_resource_info(\n    ///     \"res_type\",\n    ///     \"res_name\",\n    ///     \"owner\",\n    ///     \"description\",\n    /// );\n    /// ```\n    pub fn with_resource_info(\n        resource_type: impl Into<String>,\n        resource_name: impl Into<String>,\n        owner: impl Into<String>,\n        description: impl Into<String>,\n    ) -> Self {\n        ErrorDetails {\n            resource_info: Some(ResourceInfo::new(\n                resource_type,\n                resource_name,\n                owner,\n                description,\n            )),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`Help`] details and\n    /// remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, HelpLink};\n    ///\n    /// let err_details = ErrorDetails::with_help(vec![\n    ///     HelpLink::new(\"description of link a\", \"resource-a.example.local\"),\n    ///     HelpLink::new(\"description of link b\", \"resource-b.example.local\"),\n    /// ]);\n    /// ```\n    pub fn with_help(links: impl Into<Vec<HelpLink>>) -> Self {\n        ErrorDetails {\n            help: Some(Help::new(links)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`Help`] details (one\n    /// [`HelpLink`] set) and remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_help_link(\n    ///     \"description of link a\",\n    ///     \"resource-a.example.local\"\n    /// );\n    /// ```\n    pub fn with_help_link(description: impl Into<String>, url: impl Into<String>) -> Self {\n        ErrorDetails {\n            help: Some(Help::with_link(description, url)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Generates an [`ErrorDetails`] struct with [`LocalizedMessage`] details\n    /// and remaining fields set to `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let err_details = ErrorDetails::with_localized_message(\n    ///     \"en-US\",\n    ///     \"message for the user\"\n    /// );\n    /// ```\n    pub fn with_localized_message(locale: impl Into<String>, message: impl Into<String>) -> Self {\n        ErrorDetails {\n            localized_message: Some(LocalizedMessage::new(locale, message)),\n            ..ErrorDetails::new()\n        }\n    }\n\n    /// Get [`RetryInfo`] details, if any.\n    pub fn retry_info(&self) -> Option<&RetryInfo> {\n        self.retry_info.as_ref()\n    }\n\n    /// Get [`DebugInfo`] details, if any.\n    pub fn debug_info(&self) -> Option<&DebugInfo> {\n        self.debug_info.as_ref()\n    }\n\n    /// Get [`QuotaFailure`] details, if any.\n    pub fn quota_failure(&self) -> Option<&QuotaFailure> {\n        self.quota_failure.as_ref()\n    }\n\n    /// Get [`ErrorInfo`] details, if any.\n    pub fn error_info(&self) -> Option<&ErrorInfo> {\n        self.error_info.as_ref()\n    }\n\n    /// Get [`PreconditionFailure`] details, if any.\n    pub fn precondition_failure(&self) -> Option<&PreconditionFailure> {\n        self.precondition_failure.as_ref()\n    }\n\n    /// Get [`BadRequest`] details, if any.\n    pub fn bad_request(&self) -> Option<&BadRequest> {\n        self.bad_request.as_ref()\n    }\n\n    /// Get [`RequestInfo`] details, if any.\n    pub fn request_info(&self) -> Option<&RequestInfo> {\n        self.request_info.as_ref()\n    }\n\n    /// Get [`ResourceInfo`] details, if any.\n    pub fn resource_info(&self) -> Option<&ResourceInfo> {\n        self.resource_info.as_ref()\n    }\n\n    /// Get [`Help`] details, if any.\n    pub fn help(&self) -> Option<&Help> {\n        self.help.as_ref()\n    }\n\n    /// Get [`LocalizedMessage`] details, if any.\n    pub fn localized_message(&self) -> Option<&LocalizedMessage> {\n        self.localized_message.as_ref()\n    }\n\n    /// Set [`RetryInfo`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use std::time::Duration;\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_retry_info(Some(Duration::from_secs(5)));\n    /// ```\n    pub fn set_retry_info(&mut self, retry_delay: Option<time::Duration>) -> &mut Self {\n        self.retry_info = Some(RetryInfo::new(retry_delay));\n        self\n    }\n\n    /// Set [`DebugInfo`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// let err_stack = vec![\"...\".into(), \"...\".into()];\n    ///\n    /// err_details.set_debug_info(err_stack, \"error details\");\n    /// ```\n    pub fn set_debug_info(\n        &mut self,\n        stack_entries: impl Into<Vec<String>>,\n        detail: impl Into<String>,\n    ) -> &mut Self {\n        self.debug_info = Some(DebugInfo::new(stack_entries, detail));\n        self\n    }\n\n    /// Set [`QuotaFailure`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, QuotaViolation};\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_quota_failure(vec![\n    ///     QuotaViolation::new(\"subject 1\", \"description 1\"),\n    ///     QuotaViolation::new(\"subject 2\", \"description 2\"),\n    /// ]);\n    /// ```\n    pub fn set_quota_failure(&mut self, violations: impl Into<Vec<QuotaViolation>>) -> &mut Self {\n        self.quota_failure = Some(QuotaFailure::new(violations));\n        self\n    }\n\n    /// Adds a [`QuotaViolation`] to [`QuotaFailure`] details. Sets\n    /// [`QuotaFailure`] details if it is not set yet. Can be chained with\n    /// other `.set_` and `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.add_quota_failure_violation(\"subject\", \"description\");\n    /// ```\n    pub fn add_quota_failure_violation(\n        &mut self,\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> &mut Self {\n        match &mut self.quota_failure {\n            Some(quota_failure) => {\n                quota_failure.add_violation(subject, description);\n            }\n            None => {\n                self.quota_failure = Some(QuotaFailure::with_violation(subject, description));\n            }\n        };\n        self\n    }\n\n    /// Returns `true` if [`QuotaFailure`] is set and its `violations` vector\n    /// is not empty, otherwise returns `false`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::with_quota_failure(vec![]);\n    ///\n    /// assert_eq!(err_details.has_quota_failure_violations(), false);\n    ///\n    /// err_details.add_quota_failure_violation(\"subject\", \"description\");\n    ///\n    /// assert_eq!(err_details.has_quota_failure_violations(), true);\n    /// ```\n    pub fn has_quota_failure_violations(&self) -> bool {\n        if let Some(quota_failure) = &self.quota_failure {\n            return !quota_failure.violations.is_empty();\n        }\n        false\n    }\n\n    /// Set [`ErrorInfo`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use std::collections::HashMap;\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// let mut metadata: HashMap<String, String> = HashMap::new();\n    /// metadata.insert(\"instanceLimitPerRequest\".into(), \"100\".into());\n    ///\n    /// err_details.set_error_info(\"reason\", \"example.local\", metadata);\n    /// ```\n    pub fn set_error_info(\n        &mut self,\n        reason: impl Into<String>,\n        domain: impl Into<String>,\n        metadata: impl Into<HashMap<String, String>>,\n    ) -> &mut Self {\n        self.error_info = Some(ErrorInfo::new(reason, domain, metadata));\n        self\n    }\n\n    /// Set [`PreconditionFailure`] details. Can be chained with other `.set_`\n    /// and `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, PreconditionViolation};\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_precondition_failure(vec![\n    ///     PreconditionViolation::new(\n    ///         \"violation type 1\",\n    ///         \"subject 1\",\n    ///         \"description 1\",\n    ///     ),\n    ///     PreconditionViolation::new(\n    ///         \"violation type 2\",\n    ///         \"subject 2\",\n    ///         \"description 2\",\n    ///     ),\n    /// ]);\n    /// ```\n    pub fn set_precondition_failure(\n        &mut self,\n        violations: impl Into<Vec<PreconditionViolation>>,\n    ) -> &mut Self {\n        self.precondition_failure = Some(PreconditionFailure::new(violations));\n        self\n    }\n\n    /// Adds a [`PreconditionViolation`] to [`PreconditionFailure`] details.\n    /// Sets [`PreconditionFailure`] details if it is not set yet. Can be\n    /// chained with other `.set_` and `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.add_precondition_failure_violation(\n    ///     \"violation type\",\n    ///     \"subject\",\n    ///     \"description\"\n    /// );\n    /// ```\n    pub fn add_precondition_failure_violation(\n        &mut self,\n        violation_type: impl Into<String>,\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> &mut Self {\n        match &mut self.precondition_failure {\n            Some(precondition_failure) => {\n                precondition_failure.add_violation(violation_type, subject, description);\n            }\n            None => {\n                self.precondition_failure = Some(PreconditionFailure::with_violation(\n                    violation_type,\n                    subject,\n                    description,\n                ));\n            }\n        };\n        self\n    }\n\n    /// Returns `true` if [`PreconditionFailure`] is set and its `violations`\n    /// vector is not empty, otherwise returns `false`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::with_precondition_failure(vec![]);\n    ///\n    /// assert_eq!(err_details.has_precondition_failure_violations(), false);\n    ///\n    /// err_details.add_precondition_failure_violation(\n    ///     \"violation type\",\n    ///     \"subject\",\n    ///     \"description\"\n    /// );\n    ///\n    /// assert_eq!(err_details.has_precondition_failure_violations(), true);\n    /// ```\n    pub fn has_precondition_failure_violations(&self) -> bool {\n        if let Some(precondition_failure) = &self.precondition_failure {\n            return !precondition_failure.violations.is_empty();\n        }\n        false\n    }\n\n    /// Set [`BadRequest`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, FieldViolation};\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_bad_request(vec![\n    ///     FieldViolation::new(\"field_1\", \"description 1\"),\n    ///     FieldViolation::new(\"field_2\", \"description 2\"),\n    /// ]);\n    /// ```\n    pub fn set_bad_request(&mut self, violations: impl Into<Vec<FieldViolation>>) -> &mut Self {\n        self.bad_request = Some(BadRequest::new(violations));\n        self\n    }\n\n    /// Adds a [`FieldViolation`] to [`BadRequest`] details. Sets\n    /// [`BadRequest`] details if it is not set yet. Can be chained with other\n    /// `.set_` and `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.add_bad_request_violation(\"field\", \"description\");\n    /// ```\n    pub fn add_bad_request_violation(\n        &mut self,\n        field: impl Into<String>,\n        description: impl Into<String>,\n    ) -> &mut Self {\n        match &mut self.bad_request {\n            Some(bad_request) => {\n                bad_request.add_violation(field, description);\n            }\n            None => {\n                self.bad_request = Some(BadRequest::with_violation(field, description));\n            }\n        };\n        self\n    }\n\n    /// Returns `true` if [`BadRequest`] is set and its `field_violations`\n    /// vector is not empty, otherwise returns `false`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::with_bad_request(vec![]);\n    ///\n    /// assert_eq!(err_details.has_bad_request_violations(), false);\n    ///\n    /// err_details.add_bad_request_violation(\"field\", \"description\");\n    ///\n    /// assert_eq!(err_details.has_bad_request_violations(), true);\n    /// ```\n    pub fn has_bad_request_violations(&self) -> bool {\n        if let Some(bad_request) = &self.bad_request {\n            return !bad_request.field_violations.is_empty();\n        }\n        false\n    }\n\n    /// Set [`RequestInfo`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_request_info(\"request_id\", \"serving_data\");\n    /// ```\n    pub fn set_request_info(\n        &mut self,\n        request_id: impl Into<String>,\n        serving_data: impl Into<String>,\n    ) -> &mut Self {\n        self.request_info = Some(RequestInfo::new(request_id, serving_data));\n        self\n    }\n\n    /// Set [`ResourceInfo`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_resource_info(\"res_type\", \"res_name\", \"owner\", \"description\");\n    /// ```\n    pub fn set_resource_info(\n        &mut self,\n        resource_type: impl Into<String>,\n        resource_name: impl Into<String>,\n        owner: impl Into<String>,\n        description: impl Into<String>,\n    ) -> &mut Self {\n        self.resource_info = Some(ResourceInfo::new(\n            resource_type,\n            resource_name,\n            owner,\n            description,\n        ));\n        self\n    }\n\n    /// Set [`Help`] details. Can be chained with other `.set_` and `.add_`\n    /// [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::{ErrorDetails, HelpLink};\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_help(vec![\n    ///     HelpLink::new(\"description of link a\", \"resource-a.example.local\"),\n    ///     HelpLink::new(\"description of link b\", \"resource-b.example.local\"),\n    /// ]);\n    /// ```\n    pub fn set_help(&mut self, links: impl Into<Vec<HelpLink>>) -> &mut Self {\n        self.help = Some(Help::new(links));\n        self\n    }\n\n    /// Adds a [`HelpLink`] to [`Help`] details. Sets [`Help`] details if it is\n    /// not set yet. Can be chained with other `.set_` and `.add_`\n    /// [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.add_help_link(\"description of link\", \"resource.example.local\");\n    /// ```\n    pub fn add_help_link(\n        &mut self,\n        description: impl Into<String>,\n        url: impl Into<String>,\n    ) -> &mut Self {\n        match &mut self.help {\n            Some(help) => {\n                help.add_link(description, url);\n            }\n            None => {\n                self.help = Some(Help::with_link(description, url));\n            }\n        };\n        self\n    }\n\n    /// Returns `true` if [`Help`] is set and its `links` vector is not empty,\n    /// otherwise returns `false`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::with_help(vec![]);\n    ///\n    /// assert_eq!(err_details.has_help_links(), false);\n    ///\n    /// err_details.add_help_link(\"description of link\", \"resource.example.local\");\n    ///\n    /// assert_eq!(err_details.has_help_links(), true);\n    /// ```\n    pub fn has_help_links(&self) -> bool {\n        if let Some(help) = &self.help {\n            return !help.links.is_empty();\n        }\n        false\n    }\n\n    /// Set [`LocalizedMessage`] details. Can be chained with other `.set_` and\n    /// `.add_` [`ErrorDetails`] methods.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_types::ErrorDetails;\n    ///\n    /// let mut err_details = ErrorDetails::new();\n    ///\n    /// err_details.set_localized_message(\"en-US\", \"message for the user\");\n    /// ```\n    pub fn set_localized_message(\n        &mut self,\n        locale: impl Into<String>,\n        message: impl Into<String>,\n    ) -> &mut Self {\n        self.localized_message = Some(LocalizedMessage::new(locale, message));\n        self\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/error_details/vec.rs",
    "content": "use super::super::std_messages::{\n    BadRequest, DebugInfo, ErrorInfo, Help, LocalizedMessage, PreconditionFailure, QuotaFailure,\n    RequestInfo, ResourceInfo, RetryInfo,\n};\n\n/// Wraps the structs corresponding to the standard error messages, allowing\n/// the implementation and handling of vectors containing any of them.\n#[non_exhaustive]\n#[derive(Clone, Debug)]\npub enum ErrorDetail {\n    /// Wraps the [`RetryInfo`] struct.\n    RetryInfo(RetryInfo),\n\n    /// Wraps the [`DebugInfo`] struct.\n    DebugInfo(DebugInfo),\n\n    /// Wraps the [`QuotaFailure`] struct.\n    QuotaFailure(QuotaFailure),\n\n    /// Wraps the [`ErrorInfo`] struct.\n    ErrorInfo(ErrorInfo),\n\n    /// Wraps the [`PreconditionFailure`] struct.\n    PreconditionFailure(PreconditionFailure),\n\n    /// Wraps the [`BadRequest`] struct.\n    BadRequest(BadRequest),\n\n    /// Wraps the [`RequestInfo`] struct.\n    RequestInfo(RequestInfo),\n\n    /// Wraps the [`ResourceInfo`] struct.\n    ResourceInfo(ResourceInfo),\n\n    /// Wraps the [`Help`] struct.\n    Help(Help),\n\n    /// Wraps the [`LocalizedMessage`] struct.\n    LocalizedMessage(LocalizedMessage),\n}\n\nimpl From<RetryInfo> for ErrorDetail {\n    fn from(err_detail: RetryInfo) -> Self {\n        ErrorDetail::RetryInfo(err_detail)\n    }\n}\n\nimpl From<DebugInfo> for ErrorDetail {\n    fn from(err_detail: DebugInfo) -> Self {\n        ErrorDetail::DebugInfo(err_detail)\n    }\n}\n\nimpl From<QuotaFailure> for ErrorDetail {\n    fn from(err_detail: QuotaFailure) -> Self {\n        ErrorDetail::QuotaFailure(err_detail)\n    }\n}\n\nimpl From<ErrorInfo> for ErrorDetail {\n    fn from(err_detail: ErrorInfo) -> Self {\n        ErrorDetail::ErrorInfo(err_detail)\n    }\n}\n\nimpl From<PreconditionFailure> for ErrorDetail {\n    fn from(err_detail: PreconditionFailure) -> Self {\n        ErrorDetail::PreconditionFailure(err_detail)\n    }\n}\n\nimpl From<BadRequest> for ErrorDetail {\n    fn from(err_detail: BadRequest) -> Self {\n        ErrorDetail::BadRequest(err_detail)\n    }\n}\n\nimpl From<RequestInfo> for ErrorDetail {\n    fn from(err_detail: RequestInfo) -> Self {\n        ErrorDetail::RequestInfo(err_detail)\n    }\n}\n\nimpl From<ResourceInfo> for ErrorDetail {\n    fn from(err_detail: ResourceInfo) -> Self {\n        ErrorDetail::ResourceInfo(err_detail)\n    }\n}\n\nimpl From<Help> for ErrorDetail {\n    fn from(err_detail: Help) -> Self {\n        ErrorDetail::Help(err_detail)\n    }\n}\n\nimpl From<LocalizedMessage> for ErrorDetail {\n    fn from(err_detail: LocalizedMessage) -> Self {\n        ErrorDetail::LocalizedMessage(err_detail)\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/mod.rs",
    "content": "use prost::{\n    DecodeError, Message,\n    bytes::{Bytes, BytesMut},\n};\nuse prost_types::Any;\nuse tonic::{Code, metadata::MetadataMap};\n\nmod error_details;\nmod std_messages;\n\nuse super::pb;\n\npub use error_details::{ErrorDetails, vec::ErrorDetail};\npub use std_messages::{\n    BadRequest, DebugInfo, ErrorInfo, FieldViolation, Help, HelpLink, LocalizedMessage,\n    PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation, RequestInfo,\n    ResourceInfo, RetryInfo,\n};\n\ntrait IntoAny {\n    fn into_any(self) -> Any;\n}\n\n#[allow(dead_code)]\ntrait FromAny {\n    fn from_any(any: Any) -> Result<Self, DecodeError>\n    where\n        Self: Sized;\n}\n\ntrait FromAnyRef {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError>\n    where\n        Self: Sized;\n}\n\nfn gen_details_bytes(code: Code, message: &str, details: Vec<Any>) -> Bytes {\n    let status = pb::Status {\n        code: code as i32,\n        message: message.to_owned(),\n        details,\n    };\n\n    let mut buf = BytesMut::with_capacity(status.encoded_len());\n\n    // Should never panic since `buf` is initialized with sufficient capacity\n    status.encode(&mut buf).unwrap();\n\n    buf.freeze()\n}\n\n/// Used to implement associated functions and methods on `tonic::Status`, that\n/// allow the addition and extraction of standard error details. This trait is\n/// sealed and not meant to be implemented outside of `tonic-types`.\npub trait StatusExt: crate::sealed::Sealed {\n    /// Generates a `tonic::Status` with error details obtained from an\n    /// [`ErrorDetails`] struct, and custom metadata.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{metadata::MetadataMap, Code, Status};\n    /// use tonic_types::{ErrorDetails, StatusExt};\n    ///\n    /// let status = Status::with_error_details_and_metadata(\n    ///     Code::InvalidArgument,\n    ///     \"bad request\",\n    ///     ErrorDetails::with_bad_request_violation(\"field\", \"description\"),\n    ///     MetadataMap::new()\n    /// );\n    /// ```\n    fn with_error_details_and_metadata(\n        code: Code,\n        message: impl Into<String>,\n        details: ErrorDetails,\n        metadata: MetadataMap,\n    ) -> tonic::Status;\n\n    /// Generates a `tonic::Status` with error details obtained from an\n    /// [`ErrorDetails`] struct.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Code, Status};\n    /// use tonic_types::{ErrorDetails, StatusExt};\n    ///\n    /// let status = Status::with_error_details(\n    ///     Code::InvalidArgument,\n    ///     \"bad request\",\n    ///     ErrorDetails::with_bad_request_violation(\"field\", \"description\"),\n    /// );\n    /// ```\n    fn with_error_details(\n        code: Code,\n        message: impl Into<String>,\n        details: ErrorDetails,\n    ) -> tonic::Status;\n\n    /// Generates a `tonic::Status` with error details provided in a vector of\n    /// [`ErrorDetail`] enums, and custom metadata.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{metadata::MetadataMap, Code, Status};\n    /// use tonic_types::{BadRequest, StatusExt};\n    ///\n    /// let status = Status::with_error_details_vec_and_metadata(\n    ///     Code::InvalidArgument,\n    ///     \"bad request\",\n    ///     vec![\n    ///         BadRequest::with_violation(\"field\", \"description\").into(),\n    ///     ],\n    ///     MetadataMap::new()\n    /// );\n    /// ```\n    fn with_error_details_vec_and_metadata(\n        code: Code,\n        message: impl Into<String>,\n        details: impl IntoIterator<Item = ErrorDetail>,\n        metadata: MetadataMap,\n    ) -> tonic::Status;\n\n    /// Generates a `tonic::Status` with error details provided in a vector of\n    /// [`ErrorDetail`] enums.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Code, Status};\n    /// use tonic_types::{BadRequest, StatusExt};\n    ///\n    /// let status = Status::with_error_details_vec(\n    ///     Code::InvalidArgument,\n    ///     \"bad request\",\n    ///     vec![\n    ///         BadRequest::with_violation(\"field\", \"description\").into(),\n    ///     ]\n    /// );\n    /// ```\n    fn with_error_details_vec(\n        code: Code,\n        message: impl Into<String>,\n        details: impl IntoIterator<Item = ErrorDetail>,\n    ) -> tonic::Status;\n\n    /// Can be used to check if the error details contained in `tonic::Status`\n    /// are malformed or not. Tries to get an [`ErrorDetails`] struct from a\n    /// `tonic::Status`. If some `prost::DecodeError` occurs, it will be\n    /// returned. If not debugging, consider using\n    /// [`StatusExt::get_error_details`] or\n    /// [`StatusExt::get_error_details_vec`].\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => match status.check_error_details() {\n    ///             Ok(err_details) => {\n    ///                 // Handle extracted details\n    ///             }\n    ///             Err(decode_error) => {\n    ///                 // Handle decode_error\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn check_error_details(&self) -> Result<ErrorDetails, DecodeError>;\n\n    /// Get an [`ErrorDetails`] struct from `tonic::Status`. If some\n    /// `prost::DecodeError` occurs, an empty [`ErrorDetails`] struct will be\n    /// returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             let err_details = status.get_error_details();\n    ///             if let Some(bad_request) = err_details.bad_request() {\n    ///                 // Handle bad_request details\n    ///             }\n    ///             // ...\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_error_details(&self) -> ErrorDetails;\n\n    /// Can be used to check if the error details contained in `tonic::Status`\n    /// are malformed or not. Tries to get a vector of [`ErrorDetail`] enums\n    /// from a `tonic::Status`. If some `prost::DecodeError` occurs, it will be\n    /// returned. If not debugging, consider using\n    /// [`StatusExt::get_error_details_vec`] or\n    /// [`StatusExt::get_error_details`].\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => match status.check_error_details_vec() {\n    ///             Ok(err_details) => {\n    ///                 // Handle extracted details\n    ///             }\n    ///             Err(decode_error) => {\n    ///                 // Handle decode_error\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn check_error_details_vec(&self) -> Result<Vec<ErrorDetail>, DecodeError>;\n\n    /// Get a vector of [`ErrorDetail`] enums from `tonic::Status`. If some\n    /// `prost::DecodeError` occurs, an empty vector will be returned.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::{ErrorDetail, StatusExt};\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             let err_details = status.get_error_details_vec();\n    ///             for err_detail in err_details.iter() {\n    ///                  match err_detail {\n    ///                     ErrorDetail::BadRequest(bad_request) => {\n    ///                         // Handle bad_request details\n    ///                     }\n    ///                     // ...\n    ///                     _ => {}\n    ///                  }\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_error_details_vec(&self) -> Vec<ErrorDetail>;\n\n    /// Get first [`RetryInfo`] details found on `tonic::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(retry_info) = status.get_details_retry_info() {\n    ///                 // Handle retry_info details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_retry_info(&self) -> Option<RetryInfo>;\n\n    /// Get first [`DebugInfo`] details found on `tonic::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(debug_info) = status.get_details_debug_info() {\n    ///                 // Handle debug_info details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_debug_info(&self) -> Option<DebugInfo>;\n\n    /// Get first [`QuotaFailure`] details found on `tonic::Status`, if any.\n    /// If some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(quota_failure) = status.get_details_quota_failure() {\n    ///                 // Handle quota_failure details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_quota_failure(&self) -> Option<QuotaFailure>;\n\n    /// Get first [`ErrorInfo`] details found on `tonic::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(error_info) = status.get_details_error_info() {\n    ///                 // Handle error_info details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_error_info(&self) -> Option<ErrorInfo>;\n\n    /// Get first [`PreconditionFailure`] details found on `tonic::Status`,\n    /// if any. If some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(precondition_failure) = status.get_details_precondition_failure() {\n    ///                 // Handle precondition_failure details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_precondition_failure(&self) -> Option<PreconditionFailure>;\n\n    /// Get first [`BadRequest`] details found on `tonic::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(bad_request) = status.get_details_bad_request() {\n    ///                 // Handle bad_request details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_bad_request(&self) -> Option<BadRequest>;\n\n    /// Get first [`RequestInfo`] details found on `tonic::Status`, if any.\n    /// If some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(request_info) = status.get_details_request_info() {\n    ///                 // Handle request_info details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_request_info(&self) -> Option<RequestInfo>;\n\n    /// Get first [`ResourceInfo`] details found on `tonic::Status`, if any.\n    /// If some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(resource_info) = status.get_details_resource_info() {\n    ///                 // Handle resource_info details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_resource_info(&self) -> Option<ResourceInfo>;\n\n    /// Get first [`Help`] details found on `tonic::Status`, if any. If some\n    /// `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(help) = status.get_details_help() {\n    ///                 // Handle help details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_help(&self) -> Option<Help>;\n\n    /// Get first [`LocalizedMessage`] details found on `tonic::Status`, if\n    /// any. If some `prost::DecodeError` occurs, returns `None`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic::{Status, Response};\n    /// use tonic_types::StatusExt;\n    ///\n    /// fn handle_request_result<T>(req_result: Result<Response<T>, Status>) {\n    ///     match req_result {\n    ///         Ok(_) => {},\n    ///         Err(status) => {\n    ///             if let Some(localized_message) = status.get_details_localized_message() {\n    ///                 // Handle localized_message details\n    ///             }\n    ///         }\n    ///     };\n    /// }\n    /// ```\n    fn get_details_localized_message(&self) -> Option<LocalizedMessage>;\n}\n\nimpl crate::sealed::Sealed for tonic::Status {}\n\nimpl StatusExt for tonic::Status {\n    fn with_error_details_and_metadata(\n        code: Code,\n        message: impl Into<String>,\n        details: ErrorDetails,\n        metadata: MetadataMap,\n    ) -> Self {\n        let message: String = message.into();\n\n        let mut conv_details: Vec<Any> = Vec::with_capacity(10);\n\n        if let Some(retry_info) = details.retry_info {\n            conv_details.push(retry_info.into_any());\n        }\n\n        if let Some(debug_info) = details.debug_info {\n            conv_details.push(debug_info.into_any());\n        }\n\n        if let Some(quota_failure) = details.quota_failure {\n            conv_details.push(quota_failure.into_any());\n        }\n\n        if let Some(error_info) = details.error_info {\n            conv_details.push(error_info.into_any());\n        }\n\n        if let Some(precondition_failure) = details.precondition_failure {\n            conv_details.push(precondition_failure.into_any());\n        }\n\n        if let Some(bad_request) = details.bad_request {\n            conv_details.push(bad_request.into_any());\n        }\n\n        if let Some(request_info) = details.request_info {\n            conv_details.push(request_info.into_any());\n        }\n\n        if let Some(resource_info) = details.resource_info {\n            conv_details.push(resource_info.into_any());\n        }\n\n        if let Some(help) = details.help {\n            conv_details.push(help.into_any());\n        }\n\n        if let Some(localized_message) = details.localized_message {\n            conv_details.push(localized_message.into_any());\n        }\n\n        let details = gen_details_bytes(code, &message, conv_details);\n\n        tonic::Status::with_details_and_metadata(code, message, details, metadata)\n    }\n\n    fn with_error_details(code: Code, message: impl Into<String>, details: ErrorDetails) -> Self {\n        tonic::Status::with_error_details_and_metadata(code, message, details, MetadataMap::new())\n    }\n\n    fn with_error_details_vec_and_metadata(\n        code: Code,\n        message: impl Into<String>,\n        details: impl IntoIterator<Item = ErrorDetail>,\n        metadata: MetadataMap,\n    ) -> Self {\n        let message: String = message.into();\n\n        let mut conv_details: Vec<Any> = Vec::new();\n\n        for error_detail in details.into_iter() {\n            match error_detail {\n                ErrorDetail::RetryInfo(retry_info) => {\n                    conv_details.push(retry_info.into_any());\n                }\n                ErrorDetail::DebugInfo(debug_info) => {\n                    conv_details.push(debug_info.into_any());\n                }\n                ErrorDetail::QuotaFailure(quota_failure) => {\n                    conv_details.push(quota_failure.into_any());\n                }\n                ErrorDetail::ErrorInfo(error_info) => {\n                    conv_details.push(error_info.into_any());\n                }\n                ErrorDetail::PreconditionFailure(prec_failure) => {\n                    conv_details.push(prec_failure.into_any());\n                }\n                ErrorDetail::BadRequest(bad_req) => {\n                    conv_details.push(bad_req.into_any());\n                }\n                ErrorDetail::RequestInfo(req_info) => {\n                    conv_details.push(req_info.into_any());\n                }\n                ErrorDetail::ResourceInfo(res_info) => {\n                    conv_details.push(res_info.into_any());\n                }\n                ErrorDetail::Help(help) => {\n                    conv_details.push(help.into_any());\n                }\n                ErrorDetail::LocalizedMessage(loc_message) => {\n                    conv_details.push(loc_message.into_any());\n                }\n            }\n        }\n\n        let details = gen_details_bytes(code, &message, conv_details);\n\n        tonic::Status::with_details_and_metadata(code, message, details, metadata)\n    }\n\n    fn with_error_details_vec(\n        code: Code,\n        message: impl Into<String>,\n        details: impl IntoIterator<Item = ErrorDetail>,\n    ) -> Self {\n        tonic::Status::with_error_details_vec_and_metadata(\n            code,\n            message,\n            details,\n            MetadataMap::new(),\n        )\n    }\n\n    fn check_error_details(&self) -> Result<ErrorDetails, DecodeError> {\n        let status = pb::Status::decode(self.details())?;\n\n        status.check_error_details()\n    }\n\n    fn get_error_details(&self) -> ErrorDetails {\n        self.check_error_details().unwrap_or_default()\n    }\n\n    fn check_error_details_vec(&self) -> Result<Vec<ErrorDetail>, DecodeError> {\n        let status = pb::Status::decode(self.details())?;\n\n        status.check_error_details_vec()\n    }\n\n    fn get_error_details_vec(&self) -> Vec<ErrorDetail> {\n        self.check_error_details_vec().unwrap_or_default()\n    }\n\n    fn get_details_retry_info(&self) -> Option<RetryInfo> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_retry_info()\n    }\n\n    fn get_details_debug_info(&self) -> Option<DebugInfo> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_debug_info()\n    }\n\n    fn get_details_quota_failure(&self) -> Option<QuotaFailure> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_quota_failure()\n    }\n\n    fn get_details_error_info(&self) -> Option<ErrorInfo> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_error_info()\n    }\n\n    fn get_details_precondition_failure(&self) -> Option<PreconditionFailure> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_precondition_failure()\n    }\n\n    fn get_details_bad_request(&self) -> Option<BadRequest> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_bad_request()\n    }\n\n    fn get_details_request_info(&self) -> Option<RequestInfo> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_request_info()\n    }\n\n    fn get_details_resource_info(&self) -> Option<ResourceInfo> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_resource_info()\n    }\n\n    fn get_details_help(&self) -> Option<Help> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_help()\n    }\n\n    fn get_details_localized_message(&self) -> Option<LocalizedMessage> {\n        let status = pb::Status::decode(self.details()).ok()?;\n\n        status.get_details_localized_message()\n    }\n}\n\nimpl crate::sealed::Sealed for pb::Status {}\n\n/// Used to implement associated functions and methods on `pb::Status`, that\n/// allow the extraction of standard error details. This trait is\n/// sealed and not meant to be implemented outside of `tonic-types`.\npub trait RpcStatusExt: crate::sealed::Sealed {\n    /// Can be used to check if the error details contained in `pb::Status`\n    /// are malformed or not. Tries to get an [`ErrorDetails`] struct from a\n    /// `pb::Status`. If some `prost::DecodeError` occurs, it will be\n    /// returned. If not debugging, consider using\n    /// [`RpcStatusExt::get_error_details`] or\n    /// [`RpcStatusExt::get_error_details_vec`].\n    fn check_error_details(&self) -> Result<ErrorDetails, DecodeError>;\n\n    /// Get an [`ErrorDetails`] struct from `pb::Status`. If some\n    /// `prost::DecodeError` occurs, an empty [`ErrorDetails`] struct will be\n    /// returned.\n    fn get_error_details(&self) -> ErrorDetails;\n\n    /// Can be used to check if the error details contained in `pb::Status`\n    /// are malformed or not. Tries to get a vector of [`ErrorDetail`] enums\n    /// from a `pb::Status`. If some `prost::DecodeError` occurs, it will be\n    /// returned. If not debugging, consider using\n    /// [`StatusExt::get_error_details_vec`] or\n    /// [`StatusExt::get_error_details`].\n    fn check_error_details_vec(&self) -> Result<Vec<ErrorDetail>, DecodeError>;\n\n    /// Get a vector of [`ErrorDetail`] enums from `pb::Status`. If some\n    /// `prost::DecodeError` occurs, an empty vector will be returned.\n    fn get_error_details_vec(&self) -> Vec<ErrorDetail>;\n\n    /// Get first [`RetryInfo`] details found on `pb::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_retry_info(&self) -> Option<RetryInfo>;\n\n    /// Get first [`DebugInfo`] details found on `pb::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_debug_info(&self) -> Option<DebugInfo>;\n\n    /// Get first [`QuotaFailure`] details found on `pb::Status`, if any.\n    /// If some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_quota_failure(&self) -> Option<QuotaFailure>;\n\n    /// Get first [`ErrorInfo`] details found on `pb::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_error_info(&self) -> Option<ErrorInfo>;\n\n    /// Get first [`PreconditionFailure`] details found on `pb::Status`,\n    /// if any. If some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_precondition_failure(&self) -> Option<PreconditionFailure>;\n\n    /// Get first [`BadRequest`] details found on `pb::Status`, if any. If\n    /// some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_bad_request(&self) -> Option<BadRequest>;\n\n    /// Get first [`RequestInfo`] details found on `pb::Status`, if any.\n    /// If some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_request_info(&self) -> Option<RequestInfo>;\n\n    /// Get first [`ResourceInfo`] details found on `pb::Status`, if any.\n    /// If some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_resource_info(&self) -> Option<ResourceInfo>;\n\n    /// Get first [`Help`] details found on `pb::Status`, if any. If some\n    /// `prost::DecodeError` occurs, returns `None`.\n    fn get_details_help(&self) -> Option<Help>;\n\n    /// Get first [`LocalizedMessage`] details found on `pb::Status`, if\n    /// any. If some `prost::DecodeError` occurs, returns `None`.\n    fn get_details_localized_message(&self) -> Option<LocalizedMessage>;\n}\n\nimpl RpcStatusExt for pb::Status {\n    fn check_error_details(&self) -> Result<ErrorDetails, DecodeError> {\n        let mut details = ErrorDetails::new();\n\n        for any in self.details.iter() {\n            match any.type_url.as_str() {\n                RetryInfo::TYPE_URL => {\n                    details.retry_info = Some(RetryInfo::from_any_ref(any)?);\n                }\n                DebugInfo::TYPE_URL => {\n                    details.debug_info = Some(DebugInfo::from_any_ref(any)?);\n                }\n                QuotaFailure::TYPE_URL => {\n                    details.quota_failure = Some(QuotaFailure::from_any_ref(any)?);\n                }\n                ErrorInfo::TYPE_URL => {\n                    details.error_info = Some(ErrorInfo::from_any_ref(any)?);\n                }\n                PreconditionFailure::TYPE_URL => {\n                    details.precondition_failure = Some(PreconditionFailure::from_any_ref(any)?);\n                }\n                BadRequest::TYPE_URL => {\n                    details.bad_request = Some(BadRequest::from_any_ref(any)?);\n                }\n                RequestInfo::TYPE_URL => {\n                    details.request_info = Some(RequestInfo::from_any_ref(any)?);\n                }\n                ResourceInfo::TYPE_URL => {\n                    details.resource_info = Some(ResourceInfo::from_any_ref(any)?);\n                }\n                Help::TYPE_URL => {\n                    details.help = Some(Help::from_any_ref(any)?);\n                }\n                LocalizedMessage::TYPE_URL => {\n                    details.localized_message = Some(LocalizedMessage::from_any_ref(any)?);\n                }\n                _ => {}\n            }\n        }\n\n        Ok(details)\n    }\n\n    fn get_error_details(&self) -> ErrorDetails {\n        self.check_error_details().unwrap_or_default()\n    }\n\n    fn check_error_details_vec(&self) -> Result<Vec<ErrorDetail>, DecodeError> {\n        let mut details: Vec<ErrorDetail> = Vec::with_capacity(self.details.len());\n\n        for any in self.details.iter() {\n            match any.type_url.as_str() {\n                RetryInfo::TYPE_URL => {\n                    details.push(RetryInfo::from_any_ref(any)?.into());\n                }\n                DebugInfo::TYPE_URL => {\n                    details.push(DebugInfo::from_any_ref(any)?.into());\n                }\n                QuotaFailure::TYPE_URL => {\n                    details.push(QuotaFailure::from_any_ref(any)?.into());\n                }\n                ErrorInfo::TYPE_URL => {\n                    details.push(ErrorInfo::from_any_ref(any)?.into());\n                }\n                PreconditionFailure::TYPE_URL => {\n                    details.push(PreconditionFailure::from_any_ref(any)?.into());\n                }\n                BadRequest::TYPE_URL => {\n                    details.push(BadRequest::from_any_ref(any)?.into());\n                }\n                RequestInfo::TYPE_URL => {\n                    details.push(RequestInfo::from_any_ref(any)?.into());\n                }\n                ResourceInfo::TYPE_URL => {\n                    details.push(ResourceInfo::from_any_ref(any)?.into());\n                }\n                Help::TYPE_URL => {\n                    details.push(Help::from_any_ref(any)?.into());\n                }\n                LocalizedMessage::TYPE_URL => {\n                    details.push(LocalizedMessage::from_any_ref(any)?.into());\n                }\n                _ => {}\n            }\n        }\n\n        Ok(details)\n    }\n\n    fn get_error_details_vec(&self) -> Vec<ErrorDetail> {\n        self.check_error_details_vec().unwrap_or_default()\n    }\n\n    fn get_details_retry_info(&self) -> Option<RetryInfo> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == RetryInfo::TYPE_URL {\n                if let Ok(detail) = RetryInfo::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_debug_info(&self) -> Option<DebugInfo> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == DebugInfo::TYPE_URL {\n                if let Ok(detail) = DebugInfo::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_quota_failure(&self) -> Option<QuotaFailure> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == QuotaFailure::TYPE_URL {\n                if let Ok(detail) = QuotaFailure::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_error_info(&self) -> Option<ErrorInfo> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == ErrorInfo::TYPE_URL {\n                if let Ok(detail) = ErrorInfo::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_precondition_failure(&self) -> Option<PreconditionFailure> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == PreconditionFailure::TYPE_URL {\n                if let Ok(detail) = PreconditionFailure::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_bad_request(&self) -> Option<BadRequest> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == BadRequest::TYPE_URL {\n                if let Ok(detail) = BadRequest::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_request_info(&self) -> Option<RequestInfo> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == RequestInfo::TYPE_URL {\n                if let Ok(detail) = RequestInfo::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_resource_info(&self) -> Option<ResourceInfo> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == ResourceInfo::TYPE_URL {\n                if let Ok(detail) = ResourceInfo::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_help(&self) -> Option<Help> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == Help::TYPE_URL {\n                if let Ok(detail) = Help::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n\n    fn get_details_localized_message(&self) -> Option<LocalizedMessage> {\n        for any in self.details.iter() {\n            if any.type_url.as_str() == LocalizedMessage::TYPE_URL {\n                if let Ok(detail) = LocalizedMessage::from_any_ref(any) {\n                    return Some(detail);\n                }\n            }\n        }\n\n        None\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::{collections::HashMap, time::Duration};\n    use tonic::{Code, Status};\n\n    use super::{\n        BadRequest, DebugInfo, ErrorDetails, ErrorInfo, Help, LocalizedMessage,\n        PreconditionFailure, QuotaFailure, RequestInfo, ResourceInfo, RetryInfo, StatusExt,\n    };\n\n    #[test]\n    fn gen_status_with_details() {\n        let mut metadata = HashMap::new();\n        metadata.insert(\"limitPerRequest\".into(), \"100\".into());\n\n        let mut err_details = ErrorDetails::new();\n\n        err_details\n            .set_retry_info(Some(Duration::from_secs(5)))\n            .set_debug_info(\n                vec![\"trace3\".into(), \"trace2\".into(), \"trace1\".into()],\n                \"details\",\n            )\n            .add_quota_failure_violation(\"clientip:<ip address>\", \"description\")\n            .set_error_info(\"SOME_INFO\", \"example.local\", metadata.clone())\n            .add_precondition_failure_violation(\"TOS\", \"example.local\", \"description\")\n            .add_bad_request_violation(\"field\", \"description\")\n            .set_request_info(\"request-id\", \"some-request-data\")\n            .set_resource_info(\"resource-type\", \"resource-name\", \"owner\", \"description\")\n            .add_help_link(\"link to resource\", \"resource.example.local\")\n            .set_localized_message(\"en-US\", \"message for the user\");\n\n        let fmt_details = format!(\"{err_details:?}\");\n\n        let err_details_vec = vec![\n            RetryInfo::new(Some(Duration::from_secs(5))).into(),\n            DebugInfo::new(\n                vec![\"trace3\".into(), \"trace2\".into(), \"trace1\".into()],\n                \"details\",\n            )\n            .into(),\n            QuotaFailure::with_violation(\"clientip:<ip address>\", \"description\").into(),\n            ErrorInfo::new(\"SOME_INFO\", \"example.local\", metadata).into(),\n            PreconditionFailure::with_violation(\"TOS\", \"example.local\", \"description\").into(),\n            BadRequest::with_violation(\"field\", \"description\").into(),\n            RequestInfo::new(\"request-id\", \"some-request-data\").into(),\n            ResourceInfo::new(\"resource-type\", \"resource-name\", \"owner\", \"description\").into(),\n            Help::with_link(\"link to resource\", \"resource.example.local\").into(),\n            LocalizedMessage::new(\"en-US\", \"message for the user\").into(),\n        ];\n\n        let fmt_details_vec = format!(\"{err_details_vec:?}\");\n\n        let status_from_struct = Status::with_error_details(\n            Code::InvalidArgument,\n            \"error with bad request details\",\n            err_details,\n        );\n\n        let status_from_vec = Status::with_error_details_vec(\n            Code::InvalidArgument,\n            \"error with bad request details\",\n            err_details_vec,\n        );\n\n        let ext_details = match status_from_vec.check_error_details() {\n            Ok(ext_details) => ext_details,\n            Err(err) => panic!(\"Error extracting details struct from status_from_vec: {err:?}\"),\n        };\n\n        let fmt_ext_details = format!(\"{ext_details:?}\");\n\n        assert!(\n            fmt_ext_details.eq(&fmt_details),\n            \"Extracted details struct differs from original details struct\"\n        );\n\n        let ext_details_vec = match status_from_struct.check_error_details_vec() {\n            Ok(ext_details) => ext_details,\n            Err(err) => panic!(\"Error extracting details_vec from status_from_struct: {err:?}\"),\n        };\n\n        let fmt_ext_details_vec = format!(\"{ext_details_vec:?}\");\n\n        assert!(\n            fmt_ext_details_vec.eq(&fmt_details_vec),\n            \"Extracted details vec differs from original details vec\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/bad_request.rs",
    "content": "use prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::{LocalizedMessage, richer_error::FromAnyRef};\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used at the `field_violations` field of the [`BadRequest`] struct.\n/// Describes a single bad request field.\n#[derive(Clone, Debug, Default)]\npub struct FieldViolation {\n    /// Path leading to a field in the request body. Value should be a\n    /// sequence of dot-separated identifiers that identify a protocol buffer\n    /// field.\n    pub field: String,\n\n    /// Description of why the field is bad.\n    pub description: String,\n\n    /// The reason of the field-level error. Value should be a\n    /// SCREAMING_SNAKE_CASE error identifier from the domain of the API\n    /// service.\n    pub reason: String,\n\n    /// A localized version of the field-level error.\n    pub localized_message: Option<LocalizedMessage>,\n}\n\nimpl FieldViolation {\n    /// Creates a new [`FieldViolation`] struct.\n    pub fn new(field: impl Into<String>, description: impl Into<String>) -> Self {\n        FieldViolation {\n            field: field.into(),\n            description: description.into(),\n            ..Default::default()\n        }\n    }\n}\n\nimpl From<pb::bad_request::FieldViolation> for FieldViolation {\n    fn from(value: pb::bad_request::FieldViolation) -> Self {\n        FieldViolation {\n            field: value.field,\n            description: value.description,\n            reason: value.reason,\n            localized_message: value.localized_message.map(Into::into),\n        }\n    }\n}\n\nimpl From<FieldViolation> for pb::bad_request::FieldViolation {\n    fn from(value: FieldViolation) -> Self {\n        pb::bad_request::FieldViolation {\n            field: value.field,\n            description: value.description,\n            ..Default::default()\n        }\n    }\n}\n\n/// Used to encode/decode the `BadRequest` standard error message described in\n/// [error_details.proto]. Describes violations in a client request. Focuses\n/// on the syntactic aspects of the request.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct BadRequest {\n    /// Describes all field violations of the request.\n    pub field_violations: Vec<FieldViolation>,\n}\n\nimpl BadRequest {\n    /// Type URL of the `BadRequest` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.BadRequest\";\n\n    /// Creates a new [`BadRequest`] struct.\n    pub fn new(field_violations: impl Into<Vec<FieldViolation>>) -> Self {\n        BadRequest {\n            field_violations: field_violations.into(),\n        }\n    }\n\n    /// Creates a new [`BadRequest`] struct with a single [`FieldViolation`] in\n    /// `field_violations`.\n    pub fn with_violation(field: impl Into<String>, description: impl Into<String>) -> Self {\n        BadRequest {\n            field_violations: vec![FieldViolation {\n                field: field.into(),\n                description: description.into(),\n                ..Default::default()\n            }],\n        }\n    }\n\n    /// Adds a [`FieldViolation`] to [`BadRequest`]'s `field_violations`.\n    pub fn add_violation(\n        &mut self,\n        field: impl Into<String>,\n        description: impl Into<String>,\n    ) -> &mut Self {\n        self.field_violations.append(&mut vec![FieldViolation {\n            field: field.into(),\n            description: description.into(),\n            ..Default::default()\n        }]);\n        self\n    }\n\n    /// Returns `true` if [`BadRequest`]'s `field_violations` vector is empty,\n    /// and `false` if it is not.\n    pub fn is_empty(&self) -> bool {\n        self.field_violations.is_empty()\n    }\n}\n\nimpl IntoAny for BadRequest {\n    fn into_any(self) -> Any {\n        let detail_data: pb::BadRequest = self.into();\n\n        Any {\n            type_url: BadRequest::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for BadRequest {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for BadRequest {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let bad_req = pb::BadRequest::decode(buf)?;\n\n        Ok(bad_req.into())\n    }\n}\n\nimpl From<pb::BadRequest> for BadRequest {\n    fn from(value: pb::BadRequest) -> Self {\n        BadRequest {\n            field_violations: value.field_violations.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\nimpl From<BadRequest> for pb::BadRequest {\n    fn from(value: BadRequest) -> Self {\n        pb::BadRequest {\n            field_violations: value.field_violations.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::BadRequest;\n\n    #[test]\n    fn gen_bad_request() {\n        let mut br_details = BadRequest::new(Vec::new());\n        let formatted = format!(\"{br_details:?}\");\n\n        let expected = \"BadRequest { field_violations: [] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"empty BadRequest differs from expected result\"\n        );\n\n        assert!(\n            br_details.is_empty(),\n            \"empty BadRequest returns 'false' from .is_empty()\"\n        );\n\n        br_details\n            .add_violation(\"field_a\", \"description_a\")\n            .add_violation(\"field_b\", \"description_b\");\n\n        let formatted = format!(\"{br_details:?}\");\n\n        let expected_filled = \"BadRequest { field_violations: [FieldViolation { field: \\\"field_a\\\", description: \\\"description_a\\\", reason: \\\"\\\", localized_message: None }, FieldViolation { field: \\\"field_b\\\", description: \\\"description_b\\\", reason: \\\"\\\", localized_message: None }] }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled BadRequest differs from expected result\"\n        );\n\n        assert!(\n            !br_details.is_empty(),\n            \"filled BadRequest returns 'true' from .is_empty()\"\n        );\n\n        let gen_any = br_details.into_any();\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.BadRequest\\\", value: [10, 24, 10, 7, 102, 105, 101, 108, 100, 95, 97, 18, 13, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 95, 97, 10, 24, 10, 7, 102, 105, 101, 108, 100, 95, 98, 18, 13, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 95, 98] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled BadRequest differs from expected result\"\n        );\n\n        let br_details = match BadRequest::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating BadRequest from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"BadRequest from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/debug_info.rs",
    "content": "use prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used to encode/decode the `DebugInfo` standard error message described in\n/// [error_details.proto]. Describes additional debugging info.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct DebugInfo {\n    /// Stack trace entries indicating where the error occurred.\n    pub stack_entries: Vec<String>,\n\n    /// Additional debugging information provided by the server.\n    pub detail: String,\n}\n\nimpl DebugInfo {\n    /// Type URL of the `DebugInfo` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.DebugInfo\";\n\n    /// Creates a new [`DebugInfo`] struct.\n    pub fn new(stack_entries: impl Into<Vec<String>>, detail: impl Into<String>) -> Self {\n        DebugInfo {\n            stack_entries: stack_entries.into(),\n            detail: detail.into(),\n        }\n    }\n\n    /// Returns `true` if [`DebugInfo`] fields are empty, and `false` if they\n    /// are not.\n    pub fn is_empty(&self) -> bool {\n        self.stack_entries.is_empty() && self.detail.is_empty()\n    }\n}\n\nimpl IntoAny for DebugInfo {\n    fn into_any(self) -> Any {\n        let detail_data: pb::DebugInfo = self.into();\n\n        Any {\n            type_url: DebugInfo::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for DebugInfo {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for DebugInfo {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let debug_info = pb::DebugInfo::decode(buf)?;\n\n        Ok(debug_info.into())\n    }\n}\n\nimpl From<pb::DebugInfo> for DebugInfo {\n    fn from(debug_info: pb::DebugInfo) -> Self {\n        DebugInfo {\n            stack_entries: debug_info.stack_entries,\n            detail: debug_info.detail,\n        }\n    }\n}\n\nimpl From<DebugInfo> for pb::DebugInfo {\n    fn from(debug_info: DebugInfo) -> Self {\n        pb::DebugInfo {\n            stack_entries: debug_info.stack_entries,\n            detail: debug_info.detail,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::DebugInfo;\n\n    #[test]\n    fn gen_debug_info() {\n        let debug_info = DebugInfo::new(\n            vec![\"trace 3\".into(), \"trace 2\".into(), \"trace 1\".into()],\n            \"details about the error\",\n        );\n\n        let formatted = format!(\"{debug_info:?}\");\n\n        let expected_filled = \"DebugInfo { stack_entries: [\\\"trace 3\\\", \\\"trace 2\\\", \\\"trace 1\\\"], detail: \\\"details about the error\\\" }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled DebugInfo differs from expected result\"\n        );\n\n        let gen_any = debug_info.into_any();\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.DebugInfo\\\", value: [10, 7, 116, 114, 97, 99, 101, 32, 51, 10, 7, 116, 114, 97, 99, 101, 32, 50, 10, 7, 116, 114, 97, 99, 101, 32, 49, 18, 23, 100, 101, 116, 97, 105, 108, 115, 32, 97, 98, 111, 117, 116, 32, 116, 104, 101, 32, 101, 114, 114, 111, 114] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled DebugInfo differs from expected result\"\n        );\n\n        let br_details = match DebugInfo::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating DebugInfo from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"DebugInfo from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/error_info.rs",
    "content": "use std::collections::HashMap;\n\nuse prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used to encode/decode the `ErrorInfo` standard error message described in\n/// [error_details.proto]. Describes the cause of the error with structured\n/// details.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct ErrorInfo {\n    /// Reason of the error. Should be a constant value that identifies the\n    /// proximate cause of the error. Error reasons should be unique within a\n    /// particular domain of errors. This should be at most 63 characters and\n    /// match `/[A-Z0-9_]+/`.\n    pub reason: String,\n\n    /// Logical grouping to which the \"reason\" belongs. Normally is the\n    /// registered name of the service that generates the error.\n    pub domain: String,\n\n    /// Additional structured details about this error. Keys should match\n    /// `/[a-zA-Z0-9-_]/` and be limited to 64 characters in length.\n    pub metadata: HashMap<String, String>,\n}\n\nimpl ErrorInfo {\n    /// Type URL of the `ErrorInfo` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.ErrorInfo\";\n\n    /// Creates a new [`ErrorInfo`] struct.\n    pub fn new(\n        reason: impl Into<String>,\n        domain: impl Into<String>,\n        metadata: impl Into<HashMap<String, String>>,\n    ) -> Self {\n        ErrorInfo {\n            reason: reason.into(),\n            domain: domain.into(),\n            metadata: metadata.into(),\n        }\n    }\n\n    /// Returns `true` if [`ErrorInfo`] fields are empty, and `false` if they\n    /// are not.\n    pub fn is_empty(&self) -> bool {\n        self.reason.is_empty() && self.domain.is_empty() && self.metadata.is_empty()\n    }\n}\n\nimpl IntoAny for ErrorInfo {\n    fn into_any(self) -> Any {\n        let detail_data: pb::ErrorInfo = self.into();\n\n        Any {\n            type_url: ErrorInfo::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for ErrorInfo {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for ErrorInfo {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let error_info = pb::ErrorInfo::decode(buf)?;\n\n        Ok(error_info.into())\n    }\n}\n\nimpl From<pb::ErrorInfo> for ErrorInfo {\n    fn from(error_info: pb::ErrorInfo) -> Self {\n        ErrorInfo {\n            reason: error_info.reason,\n            domain: error_info.domain,\n            metadata: error_info.metadata,\n        }\n    }\n}\n\nimpl From<ErrorInfo> for pb::ErrorInfo {\n    fn from(error_info: ErrorInfo) -> Self {\n        pb::ErrorInfo {\n            reason: error_info.reason,\n            domain: error_info.domain,\n            metadata: error_info.metadata,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::collections::HashMap;\n\n    use super::super::super::{FromAny, IntoAny};\n    use super::ErrorInfo;\n\n    #[test]\n    fn gen_error_info() {\n        let mut metadata = HashMap::new();\n        metadata.insert(\"instanceLimitPerRequest\".into(), \"100\".into());\n\n        let error_info = ErrorInfo::new(\"SOME_INFO\", \"mydomain.com\", metadata);\n\n        let formatted = format!(\"{error_info:?}\");\n\n        let expected_filled = \"ErrorInfo { reason: \\\"SOME_INFO\\\", domain: \\\"mydomain.com\\\", metadata: {\\\"instanceLimitPerRequest\\\": \\\"100\\\"} }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled ErrorInfo differs from expected result\"\n        );\n\n        let gen_any = error_info.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.ErrorInfo\\\", value: [10, 9, 83, 79, 77, 69, 95, 73, 78, 70, 79, 18, 12, 109, 121, 100, 111, 109, 97, 105, 110, 46, 99, 111, 109, 26, 30, 10, 23, 105, 110, 115, 116, 97, 110, 99, 101, 76, 105, 109, 105, 116, 80, 101, 114, 82, 101, 113, 117, 101, 115, 116, 18, 3, 49, 48, 48] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled ErrorInfo differs from expected result\"\n        );\n\n        let br_details = match ErrorInfo::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating ErrorInfo from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"ErrorInfo from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/help.rs",
    "content": "use prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used at the `links` field of the [`Help`] struct. Describes a URL link.\n#[derive(Clone, Debug)]\npub struct HelpLink {\n    /// Description of what the link offers.\n    pub description: String,\n\n    /// URL of the link.\n    pub url: String,\n}\n\nimpl HelpLink {\n    /// Creates a new [`HelpLink`] struct.\n    pub fn new(description: impl Into<String>, url: impl Into<String>) -> Self {\n        HelpLink {\n            description: description.into(),\n            url: url.into(),\n        }\n    }\n}\n\nimpl From<pb::help::Link> for HelpLink {\n    fn from(value: pb::help::Link) -> Self {\n        HelpLink {\n            description: value.description,\n            url: value.url,\n        }\n    }\n}\n\nimpl From<HelpLink> for pb::help::Link {\n    fn from(value: HelpLink) -> Self {\n        pb::help::Link {\n            description: value.description,\n            url: value.url,\n        }\n    }\n}\n\n/// Used to encode/decode the `Help` standard error message described in\n/// [error_details.proto]. Provides links to documentation or for performing\n/// an out-of-band action.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct Help {\n    /// Links pointing to additional information on how to handle the error.\n    pub links: Vec<HelpLink>,\n}\n\nimpl Help {\n    /// Type URL of the `Help` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.Help\";\n\n    /// Creates a new [`Help`] struct.\n    pub fn new(links: impl Into<Vec<HelpLink>>) -> Self {\n        Help {\n            links: links.into(),\n        }\n    }\n\n    /// Creates a new [`Help`] struct with a single [`HelpLink`] in `links`.\n    pub fn with_link(description: impl Into<String>, url: impl Into<String>) -> Self {\n        Help {\n            links: vec![HelpLink {\n                description: description.into(),\n                url: url.into(),\n            }],\n        }\n    }\n\n    /// Adds a [`HelpLink`] to [`Help`]'s `links` vector.\n    pub fn add_link(\n        &mut self,\n        description: impl Into<String>,\n        url: impl Into<String>,\n    ) -> &mut Self {\n        self.links.append(&mut vec![HelpLink {\n            description: description.into(),\n            url: url.into(),\n        }]);\n        self\n    }\n\n    /// Returns `true` if [`Help`]'s `links` vector is empty, and `false` if it\n    /// is not.\n    pub fn is_empty(&self) -> bool {\n        self.links.is_empty()\n    }\n}\n\nimpl IntoAny for Help {\n    fn into_any(self) -> Any {\n        let detail_data: pb::Help = self.into();\n\n        Any {\n            type_url: Help::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for Help {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for Help {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let help = pb::Help::decode(buf)?;\n\n        Ok(help.into())\n    }\n}\n\nimpl From<pb::Help> for Help {\n    fn from(value: pb::Help) -> Self {\n        Help {\n            links: value.links.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\nimpl From<Help> for pb::Help {\n    fn from(value: Help) -> Self {\n        pb::Help {\n            links: value.links.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::Help;\n\n    #[test]\n    fn gen_help() {\n        let mut help = Help::new(Vec::new());\n        let formatted = format!(\"{help:?}\");\n\n        let expected = \"Help { links: [] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"empty Help differs from expected result\"\n        );\n\n        assert!(\n            help.is_empty(),\n            \"empty Help returns 'false' from .is_empty()\"\n        );\n\n        help.add_link(\"link to resource a\", \"resource-a.example.local\")\n            .add_link(\"link to resource b\", \"resource-b.example.local\");\n\n        let formatted = format!(\"{help:?}\");\n\n        let expected_filled = \"Help { links: [HelpLink { description: \\\"link to resource a\\\", url: \\\"resource-a.example.local\\\" }, HelpLink { description: \\\"link to resource b\\\", url: \\\"resource-b.example.local\\\" }] }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled Help differs from expected result\"\n        );\n\n        assert!(\n            !help.is_empty(),\n            \"filled Help returns 'true' from .is_empty()\"\n        );\n\n        let gen_any = help.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.Help\\\", value: [10, 46, 10, 18, 108, 105, 110, 107, 32, 116, 111, 32, 114, 101, 115, 111, 117, 114, 99, 101, 32, 97, 18, 24, 114, 101, 115, 111, 117, 114, 99, 101, 45, 97, 46, 101, 120, 97, 109, 112, 108, 101, 46, 108, 111, 99, 97, 108, 10, 46, 10, 18, 108, 105, 110, 107, 32, 116, 111, 32, 114, 101, 115, 111, 117, 114, 99, 101, 32, 98, 18, 24, 114, 101, 115, 111, 117, 114, 99, 101, 45, 98, 46, 101, 120, 97, 109, 112, 108, 101, 46, 108, 111, 99, 97, 108] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled Help differs from expected result\"\n        );\n\n        let br_details = match Help::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating Help from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"Help from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/loc_message.rs",
    "content": "use prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used to encode/decode the `LocalizedMessage` standard error message\n/// described in [error_details.proto]. Provides a localized error message\n/// that is safe to return to the user.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug, Default)]\npub struct LocalizedMessage {\n    /// Locale used, following the specification defined in [BCP 47]. For\n    /// example: \"en-US\", \"fr-CH\" or \"es-MX\".\n    ///\n    /// [BCP 47]: http://www.rfc-editor.org/rfc/bcp/bcp47.txt\n    pub locale: String,\n\n    /// Message corresponding to the locale.\n    pub message: String,\n}\n\nimpl LocalizedMessage {\n    /// Type URL of the `LocalizedMessage` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.LocalizedMessage\";\n\n    /// Creates a new [`LocalizedMessage`] struct.\n    pub fn new(locale: impl Into<String>, message: impl Into<String>) -> Self {\n        LocalizedMessage {\n            locale: locale.into(),\n            message: message.into(),\n        }\n    }\n\n    /// Returns `true` if [`LocalizedMessage`] fields are empty, and `false` if\n    /// they are not.\n    pub fn is_empty(&self) -> bool {\n        self.locale.is_empty() && self.message.is_empty()\n    }\n}\n\nimpl IntoAny for LocalizedMessage {\n    fn into_any(self) -> Any {\n        let detail_data: pb::LocalizedMessage = self.into();\n\n        Any {\n            type_url: LocalizedMessage::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for LocalizedMessage {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for LocalizedMessage {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let loc_message = pb::LocalizedMessage::decode(buf)?;\n\n        Ok(loc_message.into())\n    }\n}\n\nimpl From<pb::LocalizedMessage> for LocalizedMessage {\n    fn from(loc_message: pb::LocalizedMessage) -> Self {\n        LocalizedMessage {\n            locale: loc_message.locale,\n            message: loc_message.message,\n        }\n    }\n}\n\nimpl From<LocalizedMessage> for pb::LocalizedMessage {\n    fn from(loc_message: LocalizedMessage) -> Self {\n        pb::LocalizedMessage {\n            locale: loc_message.locale,\n            message: loc_message.message,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::LocalizedMessage;\n\n    #[test]\n    fn gen_localized_message() {\n        let loc_message = LocalizedMessage::new(\"en-US\", \"message for the user\");\n\n        let formatted = format!(\"{loc_message:?}\");\n\n        let expected_filled =\n            \"LocalizedMessage { locale: \\\"en-US\\\", message: \\\"message for the user\\\" }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled LocalizedMessage differs from expected result\"\n        );\n\n        let gen_any = loc_message.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.LocalizedMessage\\\", value: [10, 5, 101, 110, 45, 85, 83, 18, 20, 109, 101, 115, 115, 97, 103, 101, 32, 102, 111, 114, 32, 116, 104, 101, 32, 117, 115, 101, 114] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled LocalizedMessage differs from expected result\"\n        );\n\n        let br_details = match LocalizedMessage::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating LocalizedMessage from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"LocalizedMessage from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/mod.rs",
    "content": "mod retry_info;\n\npub use retry_info::RetryInfo;\n\nmod debug_info;\n\npub use debug_info::DebugInfo;\n\nmod quota_failure;\n\npub use quota_failure::{QuotaFailure, QuotaViolation};\n\nmod error_info;\n\npub use error_info::ErrorInfo;\n\nmod prec_failure;\n\npub use prec_failure::{PreconditionFailure, PreconditionViolation};\n\nmod bad_request;\n\npub use bad_request::{BadRequest, FieldViolation};\n\nmod request_info;\n\npub use request_info::RequestInfo;\n\nmod resource_info;\n\npub use resource_info::ResourceInfo;\n\nmod help;\n\npub use help::{Help, HelpLink};\n\nmod loc_message;\n\npub use loc_message::LocalizedMessage;\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/prec_failure.rs",
    "content": "use prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used at the `violations` field of the [`PreconditionFailure`] struct.\n/// Describes a single precondition failure.\n#[derive(Clone, Debug)]\npub struct PreconditionViolation {\n    /// Type of the PreconditionFailure. At [error_details.proto], the usage\n    /// of a service-specific enum type is recommended. For example, \"TOS\" for\n    /// a \"Terms of Service\" violation.\n    ///\n    /// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n    pub r#type: String,\n\n    /// Subject, relative to the type, that failed.\n    pub subject: String,\n\n    /// A description of how the precondition failed.\n    pub description: String,\n}\n\nimpl PreconditionViolation {\n    /// Creates a new [`PreconditionViolation`] struct.\n    pub fn new(\n        r#type: impl Into<String>,\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> Self {\n        PreconditionViolation {\n            r#type: r#type.into(),\n            subject: subject.into(),\n            description: description.into(),\n        }\n    }\n}\n\nimpl From<pb::precondition_failure::Violation> for PreconditionViolation {\n    fn from(value: pb::precondition_failure::Violation) -> Self {\n        PreconditionViolation {\n            r#type: value.r#type,\n            subject: value.subject,\n            description: value.description,\n        }\n    }\n}\n\nimpl From<PreconditionViolation> for pb::precondition_failure::Violation {\n    fn from(value: PreconditionViolation) -> Self {\n        pb::precondition_failure::Violation {\n            r#type: value.r#type,\n            subject: value.subject,\n            description: value.description,\n        }\n    }\n}\n\n/// Used to encode/decode the `PreconditionFailure` standard error message\n/// described in [error_details.proto]. Describes what preconditions have\n/// failed.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct PreconditionFailure {\n    /// Describes all precondition violations of the request.\n    pub violations: Vec<PreconditionViolation>,\n}\n\nimpl PreconditionFailure {\n    /// Type URL of the `PreconditionFailure` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.PreconditionFailure\";\n\n    /// Creates a new [`PreconditionFailure`] struct.\n    pub fn new(violations: impl Into<Vec<PreconditionViolation>>) -> Self {\n        PreconditionFailure {\n            violations: violations.into(),\n        }\n    }\n\n    /// Creates a new [`PreconditionFailure`] struct with a single\n    /// [`PreconditionViolation`] in `violations`.\n    pub fn with_violation(\n        violation_type: impl Into<String>,\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> Self {\n        PreconditionFailure {\n            violations: vec![PreconditionViolation {\n                r#type: violation_type.into(),\n                subject: subject.into(),\n                description: description.into(),\n            }],\n        }\n    }\n\n    /// Adds a [`PreconditionViolation`] to [`PreconditionFailure`]'s\n    /// `violations` vector.\n    pub fn add_violation(\n        &mut self,\n        r#type: impl Into<String>,\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> &mut Self {\n        self.violations.append(&mut vec![PreconditionViolation {\n            r#type: r#type.into(),\n            subject: subject.into(),\n            description: description.into(),\n        }]);\n        self\n    }\n\n    /// Returns `true` if [`PreconditionFailure`]'s `violations` vector is\n    /// empty, and `false` if it is not.\n    pub fn is_empty(&self) -> bool {\n        self.violations.is_empty()\n    }\n}\n\nimpl IntoAny for PreconditionFailure {\n    fn into_any(self) -> Any {\n        let detail_data: pb::PreconditionFailure = self.into();\n\n        Any {\n            type_url: PreconditionFailure::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for PreconditionFailure {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for PreconditionFailure {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let precondition_failure = pb::PreconditionFailure::decode(buf)?;\n\n        Ok(precondition_failure.into())\n    }\n}\n\nimpl From<pb::PreconditionFailure> for PreconditionFailure {\n    fn from(value: pb::PreconditionFailure) -> Self {\n        PreconditionFailure {\n            violations: value.violations.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\nimpl From<PreconditionFailure> for pb::PreconditionFailure {\n    fn from(value: PreconditionFailure) -> Self {\n        pb::PreconditionFailure {\n            violations: value.violations.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::PreconditionFailure;\n\n    #[test]\n    fn gen_prec_failure() {\n        let mut prec_failure = PreconditionFailure::new(Vec::new());\n        let formatted = format!(\"{prec_failure:?}\");\n\n        let expected = \"PreconditionFailure { violations: [] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"empty PreconditionFailure differs from expected result\"\n        );\n\n        assert!(\n            prec_failure.is_empty(),\n            \"empty PreconditionFailure returns 'false' from .is_empty()\"\n        );\n\n        prec_failure\n            .add_violation(\"TOS\", \"example.local\", \"Terms of service not accepted\")\n            .add_violation(\"FNF\", \"example.local\", \"File not found\");\n\n        let formatted = format!(\"{prec_failure:?}\");\n\n        let expected_filled = \"PreconditionFailure { violations: [PreconditionViolation { type: \\\"TOS\\\", subject: \\\"example.local\\\", description: \\\"Terms of service not accepted\\\" }, PreconditionViolation { type: \\\"FNF\\\", subject: \\\"example.local\\\", description: \\\"File not found\\\" }] }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled PreconditionFailure differs from expected result\"\n        );\n\n        assert!(\n            !prec_failure.is_empty(),\n            \"filled PreconditionFailure returns 'true' from .is_empty()\"\n        );\n\n        let gen_any = prec_failure.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.PreconditionFailure\\\", value: [10, 51, 10, 3, 84, 79, 83, 18, 13, 101, 120, 97, 109, 112, 108, 101, 46, 108, 111, 99, 97, 108, 26, 29, 84, 101, 114, 109, 115, 32, 111, 102, 32, 115, 101, 114, 118, 105, 99, 101, 32, 110, 111, 116, 32, 97, 99, 99, 101, 112, 116, 101, 100, 10, 36, 10, 3, 70, 78, 70, 18, 13, 101, 120, 97, 109, 112, 108, 101, 46, 108, 111, 99, 97, 108, 26, 14, 70, 105, 108, 101, 32, 110, 111, 116, 32, 102, 111, 117, 110, 100] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled PreconditionFailure differs from expected result\"\n        );\n\n        let br_details = match PreconditionFailure::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating PreconditionFailure from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"PreconditionFailure from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/quota_failure.rs",
    "content": "use std::collections::HashMap;\n\nuse prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used at the `violations` field of the [`QuotaFailure`] struct. Describes a\n/// single quota violation.\n#[derive(Clone, Debug, Default)]\npub struct QuotaViolation {\n    /// Subject on which the quota check failed.\n    pub subject: String,\n\n    /// Description of why the quota check failed.\n    pub description: String,\n\n    /// The API service from which the quota check originates.\n    pub api_service: String,\n\n    /// The quota check that was violated.\n    pub quota_metric: String,\n\n    /// The ID of the violated quota check.\n    pub quota_id: String,\n\n    /// The dimensions of the violated quota check.\n    pub quota_dimensions: HashMap<String, String>,\n\n    /// The quota check value at the time of violation.\n    pub quota_value: i64,\n\n    /// The future value of the quota check value when a quota check rollout is\n    /// in progress.\n    pub futura_quota_value: Option<i64>,\n}\n\nimpl QuotaViolation {\n    /// Creates a new [`QuotaViolation`] struct.\n    pub fn new(subject: impl Into<String>, description: impl Into<String>) -> Self {\n        QuotaViolation {\n            subject: subject.into(),\n            description: description.into(),\n            ..Default::default()\n        }\n    }\n}\n\nimpl From<pb::quota_failure::Violation> for QuotaViolation {\n    fn from(value: pb::quota_failure::Violation) -> Self {\n        QuotaViolation {\n            subject: value.subject,\n            description: value.description,\n            api_service: value.api_service,\n            quota_metric: value.quota_metric,\n            quota_id: value.quota_id,\n            quota_dimensions: value.quota_dimensions,\n            quota_value: value.quota_value,\n            futura_quota_value: value.future_quota_value,\n        }\n    }\n}\n\nimpl From<QuotaViolation> for pb::quota_failure::Violation {\n    fn from(value: QuotaViolation) -> Self {\n        pb::quota_failure::Violation {\n            subject: value.subject,\n            description: value.description,\n            api_service: value.api_service,\n            quota_metric: value.quota_metric,\n            quota_id: value.quota_id,\n            quota_dimensions: value.quota_dimensions,\n            quota_value: value.quota_value,\n            future_quota_value: value.futura_quota_value,\n        }\n    }\n}\n\n/// Used to encode/decode the `QuotaFailure` standard error message described\n/// in [error_details.proto]. Describes how a quota check failed.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct QuotaFailure {\n    /// Describes all quota violations.\n    pub violations: Vec<QuotaViolation>,\n}\n\nimpl QuotaFailure {\n    /// Type URL of the `QuotaFailure` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.QuotaFailure\";\n\n    /// Creates a new [`QuotaFailure`] struct.\n    pub fn new(violations: impl Into<Vec<QuotaViolation>>) -> Self {\n        QuotaFailure {\n            violations: violations.into(),\n        }\n    }\n\n    /// Creates a new [`QuotaFailure`] struct with a single [`QuotaViolation`]\n    /// in `violations`.\n    pub fn with_violation(subject: impl Into<String>, description: impl Into<String>) -> Self {\n        QuotaFailure {\n            violations: vec![QuotaViolation {\n                subject: subject.into(),\n                description: description.into(),\n                ..Default::default()\n            }],\n        }\n    }\n\n    /// Adds a [`QuotaViolation`] to [`QuotaFailure`]'s `violations`.\n    pub fn add_violation(\n        &mut self,\n        subject: impl Into<String>,\n        description: impl Into<String>,\n    ) -> &mut Self {\n        self.violations.append(&mut vec![QuotaViolation {\n            subject: subject.into(),\n            description: description.into(),\n            ..Default::default()\n        }]);\n        self\n    }\n\n    /// Returns `true` if [`QuotaFailure`]'s `violations` vector is empty, and\n    /// `false` if it is not.\n    pub fn is_empty(&self) -> bool {\n        self.violations.is_empty()\n    }\n}\n\nimpl IntoAny for QuotaFailure {\n    fn into_any(self) -> Any {\n        let detail_data: pb::QuotaFailure = self.into();\n\n        Any {\n            type_url: QuotaFailure::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for QuotaFailure {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for QuotaFailure {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let quota_failure = pb::QuotaFailure::decode(buf)?;\n\n        Ok(quota_failure.into())\n    }\n}\n\nimpl From<pb::QuotaFailure> for QuotaFailure {\n    fn from(value: pb::QuotaFailure) -> Self {\n        QuotaFailure {\n            violations: value.violations.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\nimpl From<QuotaFailure> for pb::QuotaFailure {\n    fn from(value: QuotaFailure) -> Self {\n        pb::QuotaFailure {\n            violations: value.violations.into_iter().map(Into::into).collect(),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::QuotaFailure;\n\n    #[test]\n    fn gen_quota_failure() {\n        let mut quota_failure = QuotaFailure::new(Vec::new());\n        let formatted = format!(\"{quota_failure:?}\");\n\n        let expected = \"QuotaFailure { violations: [] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"empty QuotaFailure differs from expected result\"\n        );\n\n        assert!(\n            quota_failure.is_empty(),\n            \"empty QuotaFailure returns 'false' from .is_empty()\"\n        );\n\n        quota_failure\n            .add_violation(\"clientip:<ip address>\", \"description a\")\n            .add_violation(\"project:<project id>\", \"description b\");\n\n        let formatted = format!(\"{quota_failure:?}\");\n\n        let expected_filled = \"QuotaFailure { violations: [QuotaViolation { subject: \\\"clientip:<ip address>\\\", description: \\\"description a\\\", api_service: \\\"\\\", quota_metric: \\\"\\\", quota_id: \\\"\\\", quota_dimensions: {}, quota_value: 0, futura_quota_value: None }, QuotaViolation { subject: \\\"project:<project id>\\\", description: \\\"description b\\\", api_service: \\\"\\\", quota_metric: \\\"\\\", quota_id: \\\"\\\", quota_dimensions: {}, quota_value: 0, futura_quota_value: None }] }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled QuotaFailure differs from expected result\"\n        );\n\n        assert!(\n            !quota_failure.is_empty(),\n            \"filled QuotaFailure returns 'true' from .is_empty()\"\n        );\n\n        let gen_any = quota_failure.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.QuotaFailure\\\", value: [10, 38, 10, 21, 99, 108, 105, 101, 110, 116, 105, 112, 58, 60, 105, 112, 32, 97, 100, 100, 114, 101, 115, 115, 62, 18, 13, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 32, 97, 10, 37, 10, 20, 112, 114, 111, 106, 101, 99, 116, 58, 60, 112, 114, 111, 106, 101, 99, 116, 32, 105, 100, 62, 18, 13, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 32, 98] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled QuotaFailure differs from expected result\"\n        );\n\n        let br_details = match QuotaFailure::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating QuotaFailure from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"QuotaFailure from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/request_info.rs",
    "content": "use prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used to encode/decode the `RequestInfo` standard error message described\n/// in [error_details.proto]. Contains metadata about the request that\n/// clients can attach when providing feedback.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct RequestInfo {\n    /// An opaque string that should only be interpreted by the service that\n    /// generated it. For example, an id used to identify requests in the logs.\n    pub request_id: String,\n\n    /// Any data used to serve this request. For example, an encrypted stack\n    /// trace that can be sent back to the service provider for debugging.\n    pub serving_data: String,\n}\n\nimpl RequestInfo {\n    /// Type URL of the `RequestInfo` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.RequestInfo\";\n\n    /// Creates a new [`RequestInfo`] struct.\n    pub fn new(request_id: impl Into<String>, serving_data: impl Into<String>) -> Self {\n        RequestInfo {\n            request_id: request_id.into(),\n            serving_data: serving_data.into(),\n        }\n    }\n\n    /// Returns `true` if [`RequestInfo`] fields are empty, and `false` if they\n    /// are not.\n    pub fn is_empty(&self) -> bool {\n        self.request_id.is_empty() && self.serving_data.is_empty()\n    }\n}\n\nimpl IntoAny for RequestInfo {\n    fn into_any(self) -> Any {\n        let detail_data: pb::RequestInfo = self.into();\n\n        Any {\n            type_url: RequestInfo::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for RequestInfo {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for RequestInfo {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let req_info = pb::RequestInfo::decode(buf)?;\n\n        Ok(req_info.into())\n    }\n}\n\nimpl From<pb::RequestInfo> for RequestInfo {\n    fn from(req_info: pb::RequestInfo) -> Self {\n        RequestInfo {\n            request_id: req_info.request_id,\n            serving_data: req_info.serving_data,\n        }\n    }\n}\n\nimpl From<RequestInfo> for pb::RequestInfo {\n    fn from(req_info: RequestInfo) -> Self {\n        pb::RequestInfo {\n            request_id: req_info.request_id,\n            serving_data: req_info.serving_data,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::RequestInfo;\n\n    #[test]\n    fn gen_request_info() {\n        let req_info = RequestInfo::new(\"some-id\", \"some-data\");\n\n        let formatted = format!(\"{req_info:?}\");\n\n        let expected_filled =\n            \"RequestInfo { request_id: \\\"some-id\\\", serving_data: \\\"some-data\\\" }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled RequestInfo differs from expected result\"\n        );\n\n        let gen_any = req_info.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.RequestInfo\\\", value: [10, 7, 115, 111, 109, 101, 45, 105, 100, 18, 9, 115, 111, 109, 101, 45, 100, 97, 116, 97] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled RequestInfo differs from expected result\"\n        );\n\n        let br_details = match RequestInfo::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating RequestInfo from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"RequestInfo from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/resource_info.rs",
    "content": "use prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used to encode/decode the `ResourceInfo` standard error message described\n/// in [error_details.proto]. Describes the resource that is being accessed.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct ResourceInfo {\n    /// Type of resource being accessed.\n    pub resource_type: String,\n\n    /// Name of the resource being accessed.\n    pub resource_name: String,\n\n    /// The owner of the resource (optional).\n    pub owner: String,\n\n    /// Describes the error encountered when accessing the resource.\n    pub description: String,\n}\n\nimpl ResourceInfo {\n    /// Type URL of the `ResourceInfo` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.ResourceInfo\";\n\n    /// Creates a new [`ResourceInfo`] struct.\n    pub fn new(\n        resource_type: impl Into<String>,\n        resource_name: impl Into<String>,\n        owner: impl Into<String>,\n        description: impl Into<String>,\n    ) -> Self {\n        ResourceInfo {\n            resource_type: resource_type.into(),\n            resource_name: resource_name.into(),\n            owner: owner.into(),\n            description: description.into(),\n        }\n    }\n\n    /// Returns `true` if [`ResourceInfo`] fields are empty, and `false` if\n    /// they are not.\n    pub fn is_empty(&self) -> bool {\n        self.resource_type.is_empty()\n            && self.resource_name.is_empty()\n            && self.owner.is_empty()\n            && self.description.is_empty()\n    }\n}\n\nimpl IntoAny for ResourceInfo {\n    fn into_any(self) -> Any {\n        let detail_data: pb::ResourceInfo = self.into();\n\n        Any {\n            type_url: ResourceInfo::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for ResourceInfo {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for ResourceInfo {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let res_info = pb::ResourceInfo::decode(buf)?;\n\n        Ok(res_info.into())\n    }\n}\n\nimpl From<pb::ResourceInfo> for ResourceInfo {\n    fn from(res_info: pb::ResourceInfo) -> Self {\n        ResourceInfo {\n            resource_type: res_info.resource_type,\n            resource_name: res_info.resource_name,\n            owner: res_info.owner,\n            description: res_info.description,\n        }\n    }\n}\n\nimpl From<ResourceInfo> for pb::ResourceInfo {\n    fn from(res_info: ResourceInfo) -> Self {\n        pb::ResourceInfo {\n            resource_type: res_info.resource_type,\n            resource_name: res_info.resource_name,\n            owner: res_info.owner,\n            description: res_info.description,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::super::super::{FromAny, IntoAny};\n    use super::ResourceInfo;\n\n    #[test]\n    fn gen_resource_info() {\n        let res_info = ResourceInfo::new(\"resource-type\", \"resource-name\", \"owner\", \"description\");\n\n        let formatted = format!(\"{res_info:?}\");\n\n        let expected_filled = \"ResourceInfo { resource_type: \\\"resource-type\\\", resource_name: \\\"resource-name\\\", owner: \\\"owner\\\", description: \\\"description\\\" }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled ResourceInfo differs from expected result\"\n        );\n\n        let gen_any = res_info.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.ResourceInfo\\\", value: [10, 13, 114, 101, 115, 111, 117, 114, 99, 101, 45, 116, 121, 112, 101, 18, 13, 114, 101, 115, 111, 117, 114, 99, 101, 45, 110, 97, 109, 101, 26, 5, 111, 119, 110, 101, 114, 34, 11, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled ResourceInfo differs from expected result\"\n        );\n\n        let br_details = match ResourceInfo::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating ResourceInfo from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"ResourceInfo from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-types/src/richer_error/std_messages/retry_info.rs",
    "content": "use std::time;\n\nuse prost::{DecodeError, Message};\nuse prost_types::Any;\n\nuse crate::richer_error::FromAnyRef;\n\nuse super::super::{FromAny, IntoAny, pb};\n\n/// Used to encode/decode the `RetryInfo` standard error message described in\n/// [error_details.proto]. Describes when the clients can retry a failed\n/// request.\n/// Note: When obtained from decoding `RetryInfo` messages, negative\n/// `retry_delay`'s become 0.\n///\n/// [error_details.proto]: https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto\n#[derive(Clone, Debug)]\npub struct RetryInfo {\n    /// Informs the amount of time that clients should wait before retrying.\n    pub retry_delay: Option<time::Duration>,\n}\n\nimpl RetryInfo {\n    /// Type URL of the `RetryInfo` standard error message type.\n    pub const TYPE_URL: &'static str = \"type.googleapis.com/google.rpc.RetryInfo\";\n\n    /// Should not exceed `prost_types::Duration` range. Limited to\n    /// approximately 10,000 years.\n    pub const MAX_RETRY_DELAY: time::Duration = time::Duration::new(315_576_000_000, 999_999_999);\n\n    /// Creates a new [`RetryInfo`] struct. If `retry_delay` exceeds\n    /// [`RetryInfo::MAX_RETRY_DELAY`], [`RetryInfo::MAX_RETRY_DELAY`] will\n    /// be used instead.\n    pub fn new(retry_delay: Option<time::Duration>) -> Self {\n        let retry_delay = match retry_delay {\n            Some(mut delay) => {\n                if delay > RetryInfo::MAX_RETRY_DELAY {\n                    delay = RetryInfo::MAX_RETRY_DELAY\n                }\n                Some(delay)\n            }\n            None => None,\n        };\n\n        RetryInfo { retry_delay }\n    }\n\n    /// Returns `true` if [`RetryInfo`]'s `retry_delay` is set as `None`, and\n    /// `false` if it is not.\n    pub fn is_empty(&self) -> bool {\n        self.retry_delay.is_none()\n    }\n}\n\nimpl IntoAny for RetryInfo {\n    fn into_any(self) -> Any {\n        let detail_data: pb::RetryInfo = self.into();\n\n        Any {\n            type_url: RetryInfo::TYPE_URL.to_string(),\n            value: detail_data.encode_to_vec(),\n        }\n    }\n}\n\nimpl FromAny for RetryInfo {\n    #[inline]\n    fn from_any(any: Any) -> Result<Self, DecodeError> {\n        FromAnyRef::from_any_ref(&any)\n    }\n}\n\nimpl FromAnyRef for RetryInfo {\n    fn from_any_ref(any: &Any) -> Result<Self, DecodeError> {\n        let buf: &[u8] = &any.value;\n        let retry_info = pb::RetryInfo::decode(buf)?;\n\n        Ok(retry_info.into())\n    }\n}\n\nimpl From<pb::RetryInfo> for RetryInfo {\n    fn from(retry_info: pb::RetryInfo) -> Self {\n        let retry_delay = match retry_info.retry_delay {\n            Some(duration) => {\n                // Negative retry_delays become 0\n                let duration = time::Duration::try_from(duration).unwrap_or(time::Duration::ZERO);\n                Some(duration)\n            }\n            None => None,\n        };\n\n        RetryInfo { retry_delay }\n    }\n}\n\nimpl From<RetryInfo> for pb::RetryInfo {\n    fn from(value: RetryInfo) -> Self {\n        let retry_delay = match value.retry_delay {\n            Some(duration) => {\n                // If duration is too large, uses max `prost_types::Duration`\n                let duration = match prost_types::Duration::try_from(duration) {\n                    Ok(duration) => duration,\n                    Err(_) => prost_types::Duration {\n                        seconds: 315_576_000_000,\n                        nanos: 999_999_999,\n                    },\n                };\n                Some(duration)\n            }\n            None => None,\n        };\n\n        pb::RetryInfo { retry_delay }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use core::time::Duration;\n\n    use super::super::super::{FromAny, IntoAny};\n    use super::RetryInfo;\n\n    #[test]\n    fn gen_retry_info() {\n        let retry_info = RetryInfo::new(Some(Duration::from_secs(u64::MAX)));\n\n        let formatted = format!(\"{retry_info:?}\");\n\n        let expected_filled = \"RetryInfo { retry_delay: Some(315576000000.999999999s) }\";\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"filled RetryInfo differs from expected result\"\n        );\n\n        assert!(\n            !retry_info.is_empty(),\n            \"filled RetryInfo returns 'false' from .has_retry_delay()\"\n        );\n\n        let gen_any = retry_info.into_any();\n\n        let formatted = format!(\"{gen_any:?}\");\n\n        let expected = \"Any { type_url: \\\"type.googleapis.com/google.rpc.RetryInfo\\\", value: [10, 13, 8, 128, 188, 174, 206, 151, 9, 16, 255, 147, 235, 220, 3] }\";\n\n        assert!(\n            formatted.eq(expected),\n            \"Any from filled RetryInfo differs from expected result\"\n        );\n\n        let br_details = match RetryInfo::from_any(gen_any) {\n            Err(error) => panic!(\"Error generating RetryInfo from Any: {error:?}\"),\n            Ok(from_any) => from_any,\n        };\n\n        let formatted = format!(\"{br_details:?}\");\n\n        assert!(\n            formatted.eq(expected_filled),\n            \"RetryInfo from Any differs from expected result\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-web/Cargo.toml",
    "content": "[package]\nauthors = [\"Juan Alvarez <alce@me.com>\"]\ncategories = [\"network-programming\", \"asynchronous\"]\ndescription = \"\"\"\ngrpc-web protocol translation for tonic services.\n\"\"\"\nedition = \"2024\"\nhomepage = \"https://github.com/hyperium/tonic\"\nkeywords = [\"rpc\", \"grpc\", \"grpc-web\"]\nlicense = \"MIT\"\nname = \"tonic-web\"\nreadme = \"README.md\"\nrepository = \"https://github.com/hyperium/tonic\"\nversion = \"0.14.5\"\nrust-version = { workspace = true }\n\n[dependencies]\nbase64 = \"0.22\"\nbytes = \"1\"\ntokio-stream = { version = \"0.1\", default-features = false }\nhttp = \"1\"\nhttp-body = \"1\"\npin-project = \"1\"\ntonic = { version = \"0.14.0\", path = \"../tonic\", default-features = false }\ntower-service = \"0.3\"\ntower-layer = \"0.3\"\ntracing = \"0.1\"\n\n[dev-dependencies]\ntokio = { version = \"1\", features = [\"macros\", \"rt\"] }\ntower-http = { version = \"0.6\", features = [\"cors\"] }\naxum = { version = \"0.8\", default-features = false }\n\n[lints]\nworkspace = true\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n  \"tonic::*\",\n\n  # major released\n  \"bytes::*\",\n  \"http::*\",\n  \"http_body::*\",\n\n  # not major released\n  \"futures_core::stream::Stream\",\n  \"tower_layer::Layer\",\n  \"tower_service::Service\",\n]\n"
  },
  {
    "path": "tonic-web/README.md",
    "content": "# tonic-web\n\nEnables tonic servers to handle requests from `grpc-web` clients directly,\nwithout the need of an external proxy.\n\n## Enabling tonic services\n\nThe easiest way to get started, is to call the function with your tonic service\nand allow the tonic server to accept HTTP/1.1 requests:\n\n```rust\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = \"[::1]:50051\".parse().unwrap();\n    let greeter = GreeterServer::new(MyGreeter::default());\n\n   Server::builder()\n       .accept_http1(true)\n       .layer(GrpcWebLayer::new())\n       .add_service(greeter)\n       .serve(addr)\n       .await?;\n\n   Ok(())\n}\n```\n\n## Examples\n\nSee [the examples folder][example] for a server and client example.\n\n[example]: https://github.com/hyperium/tonic/tree/master/examples/src/grpc-web\n"
  },
  {
    "path": "tonic-web/src/call.rs",
    "content": "use std::fmt;\nuse std::pin::Pin;\nuse std::task::{Context, Poll, ready};\n\nuse base64::Engine as _;\nuse bytes::{Buf, BufMut, Bytes, BytesMut};\nuse http::{HeaderMap, HeaderName, HeaderValue, header};\nuse http_body::{Body, Frame, SizeHint};\nuse pin_project::pin_project;\nuse tokio_stream::Stream;\nuse tonic::Status;\n\nuse self::content_types::*;\n\n// A grpc header is u8 (flag) + u32 (msg len)\nconst GRPC_HEADER_SIZE: usize = 1 + 4;\n\npub(crate) mod content_types {\n    use http::{HeaderMap, header::CONTENT_TYPE};\n\n    pub(crate) const GRPC_WEB: &str = \"application/grpc-web\";\n    pub(crate) const GRPC_WEB_PROTO: &str = \"application/grpc-web+proto\";\n    pub(crate) const GRPC_WEB_TEXT: &str = \"application/grpc-web-text\";\n    pub(crate) const GRPC_WEB_TEXT_PROTO: &str = \"application/grpc-web-text+proto\";\n\n    pub(crate) fn is_grpc_web(headers: &HeaderMap) -> bool {\n        matches!(\n            content_type(headers),\n            Some(GRPC_WEB) | Some(GRPC_WEB_PROTO) | Some(GRPC_WEB_TEXT) | Some(GRPC_WEB_TEXT_PROTO)\n        )\n    }\n\n    fn content_type(headers: &HeaderMap) -> Option<&str> {\n        headers.get(CONTENT_TYPE).and_then(|val| val.to_str().ok())\n    }\n}\n\nconst BUFFER_SIZE: usize = 8 * 1024;\n\nconst FRAME_HEADER_SIZE: usize = 5;\n\n// 8th (MSB) bit of the 1st gRPC frame byte\n// denotes an uncompressed trailer (as part of the body)\nconst GRPC_WEB_TRAILERS_BIT: u8 = 0b10000000;\n\n#[derive(Copy, Clone, PartialEq, Debug)]\nenum Direction {\n    Decode,\n    Encode,\n    Empty,\n}\n\n#[derive(Copy, Clone, PartialEq, Debug)]\npub(crate) enum Encoding {\n    Base64,\n    None,\n}\n\n/// HttpBody adapter for the grpc web based services.\n#[derive(Debug)]\n#[pin_project]\npub struct GrpcWebCall<B> {\n    #[pin]\n    inner: B,\n    buf: BytesMut,\n    decoded: BytesMut,\n    direction: Direction,\n    encoding: Encoding,\n    client: bool,\n    trailers: Option<HeaderMap>,\n}\n\nimpl<B: Default> Default for GrpcWebCall<B> {\n    fn default() -> Self {\n        Self {\n            inner: Default::default(),\n            buf: Default::default(),\n            decoded: Default::default(),\n            direction: Direction::Empty,\n            encoding: Encoding::None,\n            client: Default::default(),\n            trailers: Default::default(),\n        }\n    }\n}\n\nimpl<B> GrpcWebCall<B> {\n    pub(crate) fn request(inner: B, encoding: Encoding) -> Self {\n        Self::new(inner, Direction::Decode, encoding)\n    }\n\n    pub(crate) fn response(inner: B, encoding: Encoding) -> Self {\n        Self::new(inner, Direction::Encode, encoding)\n    }\n\n    pub(crate) fn client_request(inner: B) -> Self {\n        Self::new_client(inner, Direction::Encode, Encoding::None)\n    }\n\n    pub(crate) fn client_response(inner: B) -> Self {\n        Self::new_client(inner, Direction::Decode, Encoding::None)\n    }\n\n    fn new_client(inner: B, direction: Direction, encoding: Encoding) -> Self {\n        GrpcWebCall {\n            inner,\n            buf: BytesMut::with_capacity(match (direction, encoding) {\n                (Direction::Encode, Encoding::Base64) => BUFFER_SIZE,\n                _ => 0,\n            }),\n            decoded: BytesMut::with_capacity(match direction {\n                Direction::Decode => BUFFER_SIZE,\n                _ => 0,\n            }),\n            direction,\n            encoding,\n            client: true,\n            trailers: None,\n        }\n    }\n\n    fn new(inner: B, direction: Direction, encoding: Encoding) -> Self {\n        GrpcWebCall {\n            inner,\n            buf: BytesMut::with_capacity(match (direction, encoding) {\n                (Direction::Encode, Encoding::Base64) => BUFFER_SIZE,\n                _ => 0,\n            }),\n            decoded: BytesMut::with_capacity(0),\n            direction,\n            encoding,\n            client: false,\n            trailers: None,\n        }\n    }\n\n    // This is to avoid passing a slice of bytes with a length that the base64\n    // decoder would consider invalid.\n    #[inline]\n    fn max_decodable(&self) -> usize {\n        (self.buf.len() / 4) * 4\n    }\n\n    fn decode_chunk(mut self: Pin<&mut Self>) -> Result<Option<Bytes>, Status> {\n        // not enough bytes to decode\n        if self.buf.is_empty() || self.buf.len() < 4 {\n            return Ok(None);\n        }\n\n        // Split `buf` at the largest index that is multiple of 4. Decode the\n        // returned `Bytes`, keeping the rest for the next attempt to decode.\n        let index = self.max_decodable();\n\n        crate::util::base64::STANDARD\n            .decode(self.as_mut().project().buf.split_to(index))\n            .map(|decoded| Some(Bytes::from(decoded)))\n            .map_err(internal_error)\n    }\n}\n\nimpl<B> GrpcWebCall<B>\nwhere\n    B: Body,\n    B::Data: Buf,\n    B::Error: fmt::Display,\n{\n    // Poll body for data, decoding (e.g. via Base64 if necessary) and returning frames\n    // to the caller. If the caller is a client, it should look for trailers before\n    // returning these frames.\n    fn poll_decode(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Bytes>, Status>>> {\n        match self.encoding {\n            Encoding::Base64 => loop {\n                if let Some(bytes) = self.as_mut().decode_chunk()? {\n                    return Poll::Ready(Some(Ok(Frame::data(bytes))));\n                }\n\n                let this = self.as_mut().project();\n\n                match ready!(this.inner.poll_frame(cx)) {\n                    Some(Ok(frame)) if frame.is_data() => this\n                        .buf\n                        .put(frame.into_data().unwrap_or_else(|_| unreachable!())),\n                    Some(Ok(frame)) if frame.is_trailers() => {\n                        return Poll::Ready(Some(Err(internal_error(\n                            \"malformed base64 request has unencoded trailers\",\n                        ))));\n                    }\n                    Some(Ok(_)) => {\n                        return Poll::Ready(Some(Err(internal_error(\"unexpected frame type\"))));\n                    }\n                    Some(Err(e)) => return Poll::Ready(Some(Err(internal_error(e)))),\n                    None => {\n                        return if this.buf.has_remaining() {\n                            Poll::Ready(Some(Err(internal_error(\"malformed base64 request\"))))\n                        } else if let Some(trailers) = this.trailers.take() {\n                            Poll::Ready(Some(Ok(Frame::trailers(trailers))))\n                        } else {\n                            Poll::Ready(None)\n                        };\n                    }\n                }\n            },\n\n            Encoding::None => self\n                .project()\n                .inner\n                .poll_frame(cx)\n                .map_ok(|f| f.map_data(|mut d| d.copy_to_bytes(d.remaining())))\n                .map_err(internal_error),\n        }\n    }\n\n    fn poll_encode(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Bytes>, Status>>> {\n        let this = self.as_mut().project();\n\n        match ready!(this.inner.poll_frame(cx)) {\n            Some(Ok(frame)) if frame.is_data() => {\n                let mut data = frame.into_data().unwrap_or_else(|_| unreachable!());\n                let mut res = data.copy_to_bytes(data.remaining());\n\n                if *this.encoding == Encoding::Base64 {\n                    res = crate::util::base64::STANDARD.encode(res).into();\n                }\n\n                Poll::Ready(Some(Ok(Frame::data(res))))\n            }\n            Some(Ok(frame)) if frame.is_trailers() => {\n                let trailers = frame.into_trailers().unwrap_or_else(|_| unreachable!());\n                let mut res = make_trailers_frame(trailers);\n\n                if *this.encoding == Encoding::Base64 {\n                    res = crate::util::base64::STANDARD.encode(res).into();\n                }\n\n                Poll::Ready(Some(Ok(Frame::data(res))))\n            }\n            Some(Ok(_)) => Poll::Ready(Some(Err(internal_error(\"unexpected frame type\")))),\n            Some(Err(e)) => Poll::Ready(Some(Err(internal_error(e)))),\n            None => Poll::Ready(None),\n        }\n    }\n}\n\nimpl<B> Body for GrpcWebCall<B>\nwhere\n    B: Body,\n    B::Error: fmt::Display,\n{\n    type Data = Bytes;\n    type Error = Status;\n\n    fn poll_frame(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        if self.client && self.direction == Direction::Decode {\n            let mut me = self.as_mut();\n\n            loop {\n                match ready!(me.as_mut().poll_decode(cx)) {\n                    Some(Ok(incoming_buf)) if incoming_buf.is_data() => {\n                        me.as_mut()\n                            .project()\n                            .decoded\n                            .put(incoming_buf.into_data().unwrap());\n                    }\n                    Some(Ok(incoming_buf)) if incoming_buf.is_trailers() => {\n                        let trailers = incoming_buf.into_trailers().unwrap();\n                        match me.as_mut().project().trailers {\n                            Some(current_trailers) => {\n                                current_trailers.extend(trailers);\n                            }\n                            None => {\n                                me.as_mut().project().trailers.replace(trailers);\n                            }\n                        }\n                        continue;\n                    }\n                    Some(Ok(_)) => unreachable!(\"unexpected frame type\"),\n                    None => {} // No more data to decode, time to look for trailers\n                    Some(Err(e)) => return Poll::Ready(Some(Err(e))),\n                };\n\n                // Hold the incoming, decoded data until we have a full message\n                // or trailers to return.\n                let buf = me.as_mut().project().decoded;\n\n                return match find_trailers(&buf[..])? {\n                    FindTrailers::Trailer(len) => {\n                        // Extract up to len of where the trailers are at\n                        let msg_buf = buf.copy_to_bytes(len);\n                        match decode_trailers_frame(buf.split().freeze()) {\n                            Ok(Some(trailers)) => {\n                                me.as_mut().project().trailers.replace(trailers);\n                            }\n                            Err(e) => return Poll::Ready(Some(Err(e))),\n                            _ => {}\n                        }\n\n                        if msg_buf.has_remaining() {\n                            Poll::Ready(Some(Ok(Frame::data(msg_buf))))\n                        } else if let Some(trailers) = me.as_mut().project().trailers.take() {\n                            Poll::Ready(Some(Ok(Frame::trailers(trailers))))\n                        } else {\n                            Poll::Ready(None)\n                        }\n                    }\n                    FindTrailers::IncompleteBuf => continue,\n                    FindTrailers::Done(len) => Poll::Ready(match len {\n                        0 => None,\n                        _ => Some(Ok(Frame::data(buf.split_to(len).freeze()))),\n                    }),\n                };\n            }\n        }\n\n        match self.direction {\n            Direction::Decode => self.poll_decode(cx),\n            Direction::Encode => self.poll_encode(cx),\n            Direction::Empty => Poll::Ready(None),\n        }\n    }\n\n    fn is_end_stream(&self) -> bool {\n        self.inner.is_end_stream()\n    }\n\n    fn size_hint(&self) -> SizeHint {\n        self.inner.size_hint()\n    }\n}\n\nimpl<B> Stream for GrpcWebCall<B>\nwhere\n    B: Body,\n    B::Error: fmt::Display,\n{\n    type Item = Result<Frame<Bytes>, Status>;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        self.poll_frame(cx)\n    }\n}\n\nimpl Encoding {\n    pub(crate) fn from_content_type(headers: &HeaderMap) -> Encoding {\n        Self::from_header(headers.get(header::CONTENT_TYPE))\n    }\n\n    pub(crate) fn from_accept(headers: &HeaderMap) -> Encoding {\n        Self::from_header(headers.get(header::ACCEPT))\n    }\n\n    pub(crate) fn to_content_type(self) -> &'static str {\n        match self {\n            Encoding::Base64 => GRPC_WEB_TEXT_PROTO,\n            Encoding::None => GRPC_WEB_PROTO,\n        }\n    }\n\n    fn from_header(value: Option<&HeaderValue>) -> Encoding {\n        match value.and_then(|val| val.to_str().ok()) {\n            Some(GRPC_WEB_TEXT_PROTO) | Some(GRPC_WEB_TEXT) => Encoding::Base64,\n            _ => Encoding::None,\n        }\n    }\n}\n\nfn internal_error(e: impl std::fmt::Display) -> Status {\n    Status::internal(format!(\"tonic-web: {e}\"))\n}\n\n// Key-value pairs encoded as a HTTP/1 headers block (without the terminating newline)\nfn encode_trailers(trailers: HeaderMap) -> Vec<u8> {\n    trailers.iter().fold(Vec::new(), |mut acc, (key, value)| {\n        acc.put_slice(key.as_ref());\n        acc.push(b':');\n        acc.put_slice(value.as_bytes());\n        acc.put_slice(b\"\\r\\n\");\n        acc\n    })\n}\n\nfn decode_trailers_frame(mut buf: Bytes) -> Result<Option<HeaderMap>, Status> {\n    if buf.remaining() < GRPC_HEADER_SIZE {\n        return Ok(None);\n    }\n\n    buf.get_u8();\n    buf.get_u32();\n\n    let mut map = HeaderMap::new();\n    let mut temp_buf = buf.clone();\n\n    let mut trailers = Vec::new();\n    let mut cursor_pos = 0;\n\n    for (i, b) in buf.iter().enumerate() {\n        // if we are at a trailer delimiter (\\r\\n)\n        if b == &b'\\r' && buf.get(i + 1) == Some(&b'\\n') {\n            // read the bytes of the trailer passed so far\n            let trailer = temp_buf.copy_to_bytes(i - cursor_pos);\n            // increment cursor beyond the delimiter\n            cursor_pos = i + 2;\n            trailers.push(trailer);\n            if temp_buf.has_remaining() {\n                // advance buf beyond the delimiters\n                temp_buf.get_u8();\n                temp_buf.get_u8();\n            }\n        }\n    }\n\n    for trailer in trailers {\n        let Some((key, value)) = trailer\n            .iter()\n            .position(|b| *b == b':')\n            .map(|pos| trailer.split_at(pos))\n        else {\n            return Err(Status::internal(\"trailers couldn't parse key/value\"));\n        };\n\n        // Skip the ':' separator and trim leading OWS (spaces/tabs) from the value\n        let value = &value[1..]; // skip ':'\n        let value = trim_ascii_start(value);\n\n        let header_key = HeaderName::try_from(key)\n            .map_err(|e| Status::internal(format!(\"Unable to parse HeaderName: {e}\")))?;\n        let header_value = HeaderValue::try_from(value)\n            .map_err(|e| Status::internal(format!(\"Unable to parse HeaderValue: {e}\")))?;\n        map.insert(header_key, header_value);\n    }\n\n    Ok(Some(map))\n}\n\nfn trim_ascii_start(bytes: &[u8]) -> &[u8] {\n    let start = bytes\n        .iter()\n        .position(|b| !b.is_ascii_whitespace())\n        .unwrap_or(bytes.len());\n    &bytes[start..]\n}\n\nfn make_trailers_frame(trailers: HeaderMap) -> Bytes {\n    let trailers = encode_trailers(trailers);\n    let len = trailers.len();\n    assert!(len <= u32::MAX as usize);\n\n    let mut frame = BytesMut::with_capacity(len + FRAME_HEADER_SIZE);\n    frame.put_u8(GRPC_WEB_TRAILERS_BIT);\n    frame.put_u32(len as u32);\n    frame.put_slice(&trailers);\n\n    frame.freeze()\n}\n\n/// Search some buffer for grpc-web trailers headers and return\n/// its location in the original buf. If `None` is returned we did\n/// not find a trailers in this buffer either because its incomplete\n/// or the buffer just contained grpc message frames.\nfn find_trailers(buf: &[u8]) -> Result<FindTrailers, Status> {\n    let mut len = 0;\n    let mut temp_buf = buf;\n\n    loop {\n        // To check each frame, there must be at least GRPC_HEADER_SIZE\n        // amount of bytes available otherwise the buffer is incomplete.\n        if temp_buf.is_empty() || temp_buf.len() < GRPC_HEADER_SIZE {\n            return Ok(FindTrailers::Done(len));\n        }\n\n        let header = temp_buf.get_u8();\n\n        if header == GRPC_WEB_TRAILERS_BIT {\n            return Ok(FindTrailers::Trailer(len));\n        }\n\n        if !(header == 0 || header == 1) {\n            return Err(Status::internal(format!(\n                \"Invalid header bit {header} expected 0 or 1\"\n            )));\n        }\n\n        let msg_len = temp_buf.get_u32();\n\n        len += msg_len as usize + 4 + 1;\n\n        // If the msg len of a non-grpc-web trailer frame is larger than\n        // the overall buffer we know within that buffer there are no trailers.\n        if len > buf.len() {\n            return Ok(FindTrailers::IncompleteBuf);\n        }\n\n        temp_buf = &buf[len..];\n    }\n}\n\n#[derive(Debug, PartialEq, Eq)]\nenum FindTrailers {\n    Trailer(usize),\n    IncompleteBuf,\n    Done(usize),\n}\n\n#[cfg(test)]\nmod tests {\n    use tonic::Code;\n\n    use super::*;\n\n    #[test]\n    fn encoding_constructors() {\n        let cases = &[\n            (GRPC_WEB, Encoding::None),\n            (GRPC_WEB_PROTO, Encoding::None),\n            (GRPC_WEB_TEXT, Encoding::Base64),\n            (GRPC_WEB_TEXT_PROTO, Encoding::Base64),\n            (\"foo\", Encoding::None),\n        ];\n\n        let mut headers = HeaderMap::new();\n\n        for case in cases {\n            headers.insert(header::CONTENT_TYPE, case.0.parse().unwrap());\n            headers.insert(header::ACCEPT, case.0.parse().unwrap());\n\n            assert_eq!(Encoding::from_content_type(&headers), case.1, \"{}\", case.0);\n            assert_eq!(Encoding::from_accept(&headers), case.1, \"{}\", case.0);\n        }\n    }\n\n    #[test]\n    fn decode_trailers() {\n        let mut headers = HeaderMap::new();\n        headers.insert(Status::GRPC_STATUS, 0.into());\n        headers.insert(\n            Status::GRPC_MESSAGE,\n            \"this is a message\".try_into().unwrap(),\n        );\n\n        let trailers = make_trailers_frame(headers.clone());\n\n        let map = decode_trailers_frame(trailers).unwrap().unwrap();\n\n        assert_eq!(headers, map);\n    }\n\n    #[test]\n    fn find_trailers_non_buffered() {\n        // Byte version of this:\n        // b\"\\x80\\0\\0\\0\\x0fgrpc-status:0\\r\\n\"\n        let buf = [\n            128, 0, 0, 0, 15, 103, 114, 112, 99, 45, 115, 116, 97, 116, 117, 115, 58, 48, 13, 10,\n        ];\n\n        let out = find_trailers(&buf[..]).unwrap();\n\n        assert_eq!(out, FindTrailers::Trailer(0));\n    }\n\n    #[test]\n    fn find_trailers_buffered() {\n        // Byte version of this:\n        // b\"\\0\\0\\0\\0L\\n$975738af-1a17-4aea-b887-ed0bbced6093\\x1a$da609e9b-f470-4cc0-a691-3fd6a005a436\\x80\\0\\0\\0\\x0fgrpc-status:0\\r\\n\"\n        let buf = [\n            0, 0, 0, 0, 76, 10, 36, 57, 55, 53, 55, 51, 56, 97, 102, 45, 49, 97, 49, 55, 45, 52,\n            97, 101, 97, 45, 98, 56, 56, 55, 45, 101, 100, 48, 98, 98, 99, 101, 100, 54, 48, 57,\n            51, 26, 36, 100, 97, 54, 48, 57, 101, 57, 98, 45, 102, 52, 55, 48, 45, 52, 99, 99, 48,\n            45, 97, 54, 57, 49, 45, 51, 102, 100, 54, 97, 48, 48, 53, 97, 52, 51, 54, 128, 0, 0, 0,\n            15, 103, 114, 112, 99, 45, 115, 116, 97, 116, 117, 115, 58, 48, 13, 10,\n        ];\n\n        let out = find_trailers(&buf[..]).unwrap();\n\n        assert_eq!(out, FindTrailers::Trailer(81));\n\n        let trailers = decode_trailers_frame(Bytes::copy_from_slice(&buf[81..]))\n            .unwrap()\n            .unwrap();\n        let status = trailers.get(Status::GRPC_STATUS).unwrap();\n        assert_eq!(status.to_str().unwrap(), \"0\")\n    }\n\n    #[test]\n    fn find_trailers_buffered_incomplete_message() {\n        let buf = vec![\n            0, 0, 0, 9, 238, 10, 233, 19, 18, 230, 19, 10, 9, 10, 1, 120, 26, 4, 84, 69, 88, 84,\n            18, 60, 10, 58, 10, 56, 3, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 116, 104, 105, 115, 32,\n            118, 97, 108, 117, 101, 32, 119, 97, 115, 32, 119, 114, 105, 116, 116, 101, 110, 32,\n            118, 105, 97, 32, 119, 114, 105, 116, 101, 32, 100, 101, 108, 101, 103, 97, 116, 105,\n            111, 110, 33, 18, 62, 10, 60, 10, 58, 3, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 116, 104,\n            105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 97, 115, 32, 119, 114, 105, 116, 116,\n            101, 110, 32, 98, 121, 32, 97, 110, 32, 101, 109, 98, 101, 100, 100, 101, 100, 32, 114,\n            101, 112, 108, 105, 99, 97, 33, 18, 62, 10, 60, 10, 58, 3, 0, 0, 0, 46, 0, 0, 0, 0, 0,\n            0, 0, 116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 97, 115, 32, 119, 114,\n            105, 116, 116, 101, 110, 32, 98, 121, 32, 97, 110, 32, 101, 109, 98, 101, 100, 100,\n            101, 100, 32, 114, 101, 112, 108, 105, 99, 97, 33, 18, 62, 10, 60, 10, 58, 3, 0, 0, 0,\n            46, 0, 0, 0, 0, 0, 0, 0, 116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 97,\n            115, 32, 119, 114, 105, 116, 116, 101, 110, 32, 98, 121, 32, 97, 110, 32, 101, 109, 98,\n            101, 100, 100, 101, 100, 32, 114, 101, 112, 108, 105, 99, 97, 33, 18, 62, 10, 60, 10,\n            58, 3, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 116, 104, 105, 115, 32, 118, 97, 108, 117,\n            101, 32, 119, 97, 115, 32, 119, 114, 105, 116, 116, 101, 110, 32, 98, 121, 32, 97, 110,\n            32, 101, 109, 98, 101, 100, 100, 101, 100, 32, 114, 101, 112, 108, 105, 99, 97, 33, 18,\n            62, 10, 60, 10, 58, 3, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 116, 104, 105, 115, 32, 118,\n            97, 108, 117, 101, 32, 119, 97, 115, 32, 119, 114, 105, 116, 116, 101, 110, 32, 98,\n            121, 32, 97, 110, 32, 101, 109, 98, 101, 100, 100, 101, 100, 32, 114, 101, 112, 108,\n            105, 99, 97, 33, 18, 62, 10, 60, 10, 58, 3, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 116, 104,\n            105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 97, 115, 32, 119, 114, 105, 116, 116,\n            101, 110, 32, 98, 121, 32, 97, 110, 32, 101, 109, 98, 101, 100, 100, 101, 100, 32, 114,\n            101, 112, 108, 105, 99, 97, 33, 18, 62, 10, 60, 10, 58, 3, 0, 0, 0, 46, 0, 0, 0, 0, 0,\n            0, 0, 116, 104, 105, 115, 32, 118, 97, 108, 117, 101, 32, 119, 97, 115, 32, 119, 114,\n            105, 116, 116, 101, 110, 32, 98, 121, 32,\n        ];\n\n        let out = find_trailers(&buf[..]).unwrap();\n\n        assert_eq!(out, FindTrailers::IncompleteBuf);\n    }\n\n    #[test]\n    #[ignore]\n    fn find_trailers_buffered_incomplete_buf_bug() {\n        let buf = std::fs::read(\"tests/incomplete-buf-bug.bin\").unwrap();\n        let out = find_trailers(&buf[..]).unwrap_err();\n\n        assert_eq!(out.code(), Code::Internal);\n    }\n\n    #[test]\n    fn decode_multiple_trailers() {\n        let buf = b\"\\x80\\0\\0\\0\\x0fgrpc-status:0\\r\\ngrpc-message:\\r\\na:1\\r\\nb:2\\r\\n\";\n\n        let trailers = decode_trailers_frame(Bytes::copy_from_slice(&buf[..]))\n            .unwrap()\n            .unwrap();\n\n        let mut expected = HeaderMap::new();\n        expected.insert(Status::GRPC_STATUS, \"0\".parse().unwrap());\n        expected.insert(Status::GRPC_MESSAGE, \"\".parse().unwrap());\n        expected.insert(\"a\", \"1\".parse().unwrap());\n        expected.insert(\"b\", \"2\".parse().unwrap());\n\n        assert_eq!(trailers, expected);\n    }\n\n    #[test]\n    fn decode_trailers_with_space_after_colon() {\n        let buf = b\"\\x80\\0\\0\\0\\x0fgrpc-status: 0\\r\\ngrpc-message: \\r\\n\";\n\n        let trailers = decode_trailers_frame(Bytes::copy_from_slice(&buf[..]))\n            .unwrap()\n            .unwrap();\n\n        let mut expected = HeaderMap::new();\n        expected.insert(Status::GRPC_STATUS, \"0\".parse().unwrap());\n        expected.insert(Status::GRPC_MESSAGE, \"\".parse().unwrap());\n\n        assert_eq!(trailers, expected);\n    }\n\n    #[test]\n    fn decode_trailers_space_after_colon() {\n        // connect-rpc and standard HTTP use \"key: value\" (space after colon)\n        let trailers_bytes = b\"grpc-status: 0\\r\\ngrpc-message: this is a message\\r\\n\";\n        let len = trailers_bytes.len();\n\n        let mut frame = BytesMut::new();\n        frame.put_u8(GRPC_WEB_TRAILERS_BIT);\n        frame.put_u32(len as u32);\n        frame.put_slice(&trailers_bytes[..]);\n\n        let map = decode_trailers_frame(frame.freeze()).unwrap().unwrap();\n\n        let mut expected = HeaderMap::new();\n        expected.insert(Status::GRPC_STATUS, HeaderValue::from_static(\"0\"));\n        expected.insert(\n            Status::GRPC_MESSAGE,\n            HeaderValue::from_static(\"this is a message\"),\n        );\n\n        assert_eq!(map, expected);\n    }\n\n    #[test]\n    fn decode_trailers_value_with_colons() {\n        let trailers_bytes = b\"grpc-status: 0\\r\\ngrpc-message: error: something: went wrong\\r\\n\";\n        let len = trailers_bytes.len();\n\n        let mut frame = BytesMut::new();\n        frame.put_u8(GRPC_WEB_TRAILERS_BIT);\n        frame.put_u32(len as u32);\n        frame.put_slice(&trailers_bytes[..]);\n\n        let map = decode_trailers_frame(frame.freeze()).unwrap().unwrap();\n\n        assert_eq!(map.get(\"grpc-status\").unwrap(), \"0\");\n        assert_eq!(\n            map.get(\"grpc-message\").unwrap(),\n            \"error: something: went wrong\"\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-web/src/client.rs",
    "content": "use http::header::CONTENT_TYPE;\nuse http::{Request, Response, Version};\nuse pin_project::pin_project;\nuse std::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll, ready};\nuse tower_layer::Layer;\nuse tower_service::Service;\nuse tracing::debug;\n\nuse crate::call::GrpcWebCall;\nuse crate::call::content_types::GRPC_WEB;\n\n/// Layer implementing the grpc-web protocol for clients.\n#[derive(Debug, Default, Clone)]\npub struct GrpcWebClientLayer {\n    _priv: (),\n}\n\nimpl GrpcWebClientLayer {\n    /// Create a new grpc-web for clients layer.\n    pub fn new() -> GrpcWebClientLayer {\n        Self::default()\n    }\n}\n\nimpl<S> Layer<S> for GrpcWebClientLayer {\n    type Service = GrpcWebClientService<S>;\n\n    fn layer(&self, inner: S) -> Self::Service {\n        GrpcWebClientService::new(inner)\n    }\n}\n\n/// A [`Service`] that wraps some inner http service that will\n/// coerce requests coming from [`tonic::client::Grpc`] into proper\n/// `grpc-web` requests.\n#[derive(Debug, Clone)]\npub struct GrpcWebClientService<S> {\n    inner: S,\n}\n\nimpl<S> GrpcWebClientService<S> {\n    /// Create a new grpc-web for clients service.\n    pub fn new(inner: S) -> Self {\n        Self { inner }\n    }\n}\n\nimpl<S, B1, B2> Service<Request<B1>> for GrpcWebClientService<S>\nwhere\n    S: Service<Request<GrpcWebCall<B1>>, Response = Response<B2>>,\n{\n    type Response = Response<GrpcWebCall<B2>>;\n    type Error = S::Error;\n    type Future = ResponseFuture<S::Future>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, mut req: Request<B1>) -> Self::Future {\n        if req.version() == Version::HTTP_2 {\n            debug!(\"coercing HTTP2 request to HTTP1.1\");\n\n            *req.version_mut() = Version::HTTP_11;\n        }\n\n        req.headers_mut()\n            .insert(CONTENT_TYPE, GRPC_WEB.try_into().unwrap());\n\n        let req = req.map(GrpcWebCall::client_request);\n\n        let fut = self.inner.call(req);\n\n        ResponseFuture { inner: fut }\n    }\n}\n\n/// Response future for the [`GrpcWebService`](crate::GrpcWebService).\n#[pin_project]\n#[must_use = \"futures do nothing unless polled\"]\npub struct ResponseFuture<F> {\n    #[pin]\n    inner: F,\n}\n\nimpl<F, B, E> Future for ResponseFuture<F>\nwhere\n    F: Future<Output = Result<Response<B>, E>>,\n{\n    type Output = Result<Response<GrpcWebCall<B>>, E>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let res = ready!(self.project().inner.poll(cx));\n\n        Poll::Ready(res.map(|r| r.map(GrpcWebCall::client_response)))\n    }\n}\n\nimpl<F> fmt::Debug for ResponseFuture<F> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ResponseFuture\").finish()\n    }\n}\n"
  },
  {
    "path": "tonic-web/src/layer.rs",
    "content": "use super::GrpcWebService;\n\nuse tower_layer::Layer;\n\n/// Layer implementing the grpc-web protocol.\n#[derive(Debug, Default, Clone)]\npub struct GrpcWebLayer {\n    _priv: (),\n}\n\nimpl GrpcWebLayer {\n    /// Create a new grpc-web layer.\n    pub fn new() -> GrpcWebLayer {\n        Self::default()\n    }\n}\n\nimpl<S> Layer<S> for GrpcWebLayer {\n    type Service = GrpcWebService<S>;\n\n    fn layer(&self, inner: S) -> Self::Service {\n        GrpcWebService::new(inner)\n    }\n}\n"
  },
  {
    "path": "tonic-web/src/lib.rs",
    "content": "//! grpc-web protocol translation for [`tonic`] services.\n//!\n//! [`tonic_web`] enables tonic servers to handle requests from [grpc-web] clients directly,\n//! without the need of an external proxy. It achieves this by wrapping individual tonic services\n//! with a [tower] service that performs the translation between protocols and handles `cors`\n//! requests.\n//!\n//! ## Enabling tonic services\n//!\n//! You can customize the CORS configuration composing the [`GrpcWebLayer`] with the cors layer of your choice.\n//!\n//! ```ignore\n//! #[tokio::main]\n//! async fn main() -> Result<(), Box<dyn std::error::Error>> {\n//!     let addr = \"[::1]:50051\".parse().unwrap();\n//!     let greeter = GreeterServer::new(MyGreeter::default());\n//!\n//!     Server::builder()\n//!        .accept_http1(true)\n//!        // This will apply the gRPC-Web translation layer\n//!        .layer(GrpcWebLayer::new())\n//!        .add_service(greeter)\n//!        .serve(addr)\n//!        .await?;\n//!\n//!    Ok(())\n//! }\n//! ```\n//!\n//! Alternatively, if you have a tls enabled server, you could skip setting `accept_http1` to `true`.\n//! This works because the browser will handle `ALPN`.\n//!\n//! ```ignore\n//! #[tokio::main]\n//! async fn main() -> Result<(), Box<dyn std::error::Error>> {\n//!     let cert = tokio::fs::read(\"server.pem\").await?;\n//!     let key = tokio::fs::read(\"server.key\").await?;\n//!     let identity = Identity::from_pem(cert, key);\n//!\n//!     let addr = \"[::1]:50051\".parse().unwrap();\n//!     let greeter = GreeterServer::new(MyGreeter::default());\n//!\n//!     // No need to enable HTTP/1\n//!     Server::builder()\n//!        .tls_config(ServerTlsConfig::new().identity(identity))?\n//!        .layer(GrpcWebLayer::new())\n//!        .add_service(greeter)\n//!        .serve(addr)\n//!        .await?;\n//!\n//!    Ok(())\n//! }\n//! ```\n//!\n//! ## Limitations\n//!\n//! * `tonic_web` is designed to work with grpc-web-compliant clients only. It is not expected to\n//!   handle arbitrary HTTP/x.x requests or bespoke protocols.\n//! * Similarly, the cors support implemented  by this crate will *only* handle grpc-web and\n//!   grpc-web preflight requests.\n//! * Currently, grpc-web clients can only perform `unary` and `server-streaming` calls. These\n//!   are the only requests this crate is designed to handle. Support for client and bi-directional\n//!   streaming will be officially supported when clients do.\n//! * There is no support for web socket transports.\n//!\n//!\n//! [`tonic`]: https://github.com/hyperium/tonic\n//! [`tonic_web`]: https://github.com/hyperium/tonic\n//! [grpc-web]: https://github.com/grpc/grpc-web\n//! [tower]: https://github.com/tower-rs/tower\n#![doc(issue_tracker_base_url = \"https://github.com/hyperium/tonic/issues/\")]\n\npub use call::GrpcWebCall;\npub use client::{GrpcWebClientLayer, GrpcWebClientService};\npub use layer::GrpcWebLayer;\npub use service::{GrpcWebService, ResponseFuture};\n\nmod call;\nmod client;\nmod layer;\nmod service;\n\ntype BoxError = Box<dyn std::error::Error + Send + Sync>;\n\npub(crate) mod util {\n    pub(crate) mod base64 {\n        use base64::{\n            alphabet,\n            engine::{\n                DecodePaddingMode,\n                general_purpose::{GeneralPurpose, GeneralPurposeConfig},\n            },\n        };\n\n        pub(crate) const STANDARD: GeneralPurpose = GeneralPurpose::new(\n            &alphabet::STANDARD,\n            GeneralPurposeConfig::new()\n                .with_encode_padding(true)\n                .with_decode_padding_mode(DecodePaddingMode::Indifferent),\n        );\n    }\n}\n"
  },
  {
    "path": "tonic-web/src/service.rs",
    "content": "use core::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll, ready};\n\nuse http::{HeaderMap, HeaderValue, Method, Request, Response, StatusCode, Version, header};\nuse pin_project::pin_project;\nuse tonic::metadata::GRPC_CONTENT_TYPE;\nuse tonic::{body::Body, server::NamedService};\nuse tower_service::Service;\nuse tracing::{debug, trace};\n\nuse crate::call::content_types::is_grpc_web;\nuse crate::call::{Encoding, GrpcWebCall};\n\n/// Service implementing the grpc-web protocol.\n#[derive(Debug, Clone)]\npub struct GrpcWebService<S> {\n    inner: S,\n}\n\n#[derive(Debug, PartialEq)]\nenum RequestKind<'a> {\n    // The request is considered a grpc-web request if its `content-type`\n    // header is exactly one of:\n    //\n    //  - \"application/grpc-web\"\n    //  - \"application/grpc-web+proto\"\n    //  - \"application/grpc-web-text\"\n    //  - \"application/grpc-web-text+proto\"\n    GrpcWeb {\n        method: &'a Method,\n        encoding: Encoding,\n        accept: Encoding,\n    },\n    // All other requests, including `application/grpc`\n    Other(http::Version),\n}\n\nimpl<S> GrpcWebService<S> {\n    pub(crate) fn new(inner: S) -> Self {\n        GrpcWebService { inner }\n    }\n}\n\nimpl<S, ReqBody, ResBody> Service<Request<ReqBody>> for GrpcWebService<S>\nwhere\n    S: Service<Request<Body>, Response = Response<ResBody>>,\n    ReqBody: http_body::Body<Data = bytes::Bytes> + Send + 'static,\n    ReqBody::Error: Into<crate::BoxError> + fmt::Display,\n    ResBody: http_body::Body<Data = bytes::Bytes> + Send + 'static,\n    ResBody::Error: Into<crate::BoxError> + fmt::Display,\n{\n    type Response = Response<Body>;\n    type Error = S::Error;\n    type Future = ResponseFuture<S::Future>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, req: Request<ReqBody>) -> Self::Future {\n        match RequestKind::new(req.headers(), req.method(), req.version()) {\n            // A valid grpc-web request, regardless of HTTP version.\n            //\n            // If the request includes an `origin` header, we verify it is allowed\n            // to access the resource, an HTTP 403 response is returned otherwise.\n            //\n            // If the origin is allowed to access the resource or there is no\n            // `origin` header present, translate the request into a grpc request,\n            // call the inner service, and translate the response back to\n            // grpc-web.\n            RequestKind::GrpcWeb {\n                method: &Method::POST,\n                encoding,\n                accept,\n            } => {\n                trace!(kind = \"simple\", path = ?req.uri().path(), ?encoding, ?accept);\n\n                ResponseFuture {\n                    case: Case::GrpcWeb {\n                        future: self.inner.call(coerce_request(req, encoding)),\n                        accept,\n                    },\n                }\n            }\n\n            // The request's content-type matches one of the 4 supported grpc-web\n            // content-types, but the request method is not `POST`.\n            // This is not a valid grpc-web request, return HTTP 405.\n            RequestKind::GrpcWeb { .. } => {\n                debug!(kind = \"simple\", error=\"method not allowed\", method = ?req.method());\n\n                ResponseFuture {\n                    case: Case::immediate(StatusCode::METHOD_NOT_ALLOWED),\n                }\n            }\n\n            // All http/2 requests that are not grpc-web are passed through to the inner service,\n            // whatever they are.\n            RequestKind::Other(Version::HTTP_2) => {\n                debug!(kind = \"other h2\", content_type = ?req.headers().get(header::CONTENT_TYPE));\n                ResponseFuture {\n                    case: Case::Other {\n                        future: self.inner.call(req.map(Body::new)),\n                    },\n                }\n            }\n\n            // Return HTTP 400 for all other requests.\n            RequestKind::Other(_) => {\n                debug!(kind = \"other h1\", content_type = ?req.headers().get(header::CONTENT_TYPE));\n\n                ResponseFuture {\n                    case: Case::immediate(StatusCode::BAD_REQUEST),\n                }\n            }\n        }\n    }\n}\n\n/// Response future for the [`GrpcWebService`].\n#[pin_project]\n#[must_use = \"futures do nothing unless polled\"]\npub struct ResponseFuture<F> {\n    #[pin]\n    case: Case<F>,\n}\n\n#[pin_project(project = CaseProj)]\nenum Case<F> {\n    GrpcWeb {\n        #[pin]\n        future: F,\n        accept: Encoding,\n    },\n    Other {\n        #[pin]\n        future: F,\n    },\n    ImmediateResponse {\n        res: Option<http::response::Parts>,\n    },\n}\n\nimpl<F> Case<F> {\n    fn immediate(status: StatusCode) -> Self {\n        let (res, ()) = Response::builder()\n            .status(status)\n            .body(())\n            .unwrap()\n            .into_parts();\n        Self::ImmediateResponse { res: Some(res) }\n    }\n}\n\nimpl<F, B, E> Future for ResponseFuture<F>\nwhere\n    F: Future<Output = Result<Response<B>, E>>,\n    B: http_body::Body<Data = bytes::Bytes> + Send + 'static,\n    B::Error: Into<crate::BoxError> + fmt::Display,\n{\n    type Output = Result<Response<Body>, E>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this = self.project();\n\n        match this.case.project() {\n            CaseProj::GrpcWeb { future, accept } => {\n                let res = ready!(future.poll(cx))?;\n\n                Poll::Ready(Ok(coerce_response(res, *accept)))\n            }\n            CaseProj::Other { future } => future.poll(cx).map_ok(|res| res.map(Body::new)),\n            CaseProj::ImmediateResponse { res } => {\n                let res = Response::from_parts(res.take().unwrap(), Body::empty());\n                Poll::Ready(Ok(res))\n            }\n        }\n    }\n}\n\nimpl<S: NamedService> NamedService for GrpcWebService<S> {\n    const NAME: &'static str = S::NAME;\n}\n\nimpl<F> fmt::Debug for ResponseFuture<F> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"ResponseFuture\").finish()\n    }\n}\n\nimpl<'a> RequestKind<'a> {\n    fn new(headers: &'a HeaderMap, method: &'a Method, version: Version) -> Self {\n        if is_grpc_web(headers) {\n            return RequestKind::GrpcWeb {\n                method,\n                encoding: Encoding::from_content_type(headers),\n                accept: Encoding::from_accept(headers),\n            };\n        }\n\n        RequestKind::Other(version)\n    }\n}\n\n// Mutating request headers to conform to a gRPC request is not really\n// necessary for us at this point. We could remove most of these except\n// maybe for inserting `header::TE`, which tonic should check?\nfn coerce_request<B>(mut req: Request<B>, encoding: Encoding) -> Request<Body>\nwhere\n    B: http_body::Body<Data = bytes::Bytes> + Send + 'static,\n    B::Error: Into<crate::BoxError> + fmt::Display,\n{\n    req.headers_mut().remove(header::CONTENT_LENGTH);\n\n    req.headers_mut()\n        .insert(header::CONTENT_TYPE, GRPC_CONTENT_TYPE);\n\n    req.headers_mut()\n        .insert(header::TE, HeaderValue::from_static(\"trailers\"));\n\n    req.headers_mut().insert(\n        header::ACCEPT_ENCODING,\n        HeaderValue::from_static(\"identity,deflate,gzip\"),\n    );\n\n    req.map(|b| Body::new(GrpcWebCall::request(b, encoding)))\n}\n\nfn coerce_response<B>(res: Response<B>, encoding: Encoding) -> Response<Body>\nwhere\n    B: http_body::Body<Data = bytes::Bytes> + Send + 'static,\n    B::Error: Into<crate::BoxError> + fmt::Display,\n{\n    let mut res = res\n        .map(|b| GrpcWebCall::response(b, encoding))\n        .map(Body::new);\n\n    res.headers_mut().insert(\n        header::CONTENT_TYPE,\n        HeaderValue::from_static(encoding.to_content_type()),\n    );\n\n    res\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::call::content_types::*;\n    use http::header::{\n        ACCESS_CONTROL_REQUEST_HEADERS, ACCESS_CONTROL_REQUEST_METHOD, CONTENT_TYPE, ORIGIN,\n    };\n    use tower_layer::Layer as _;\n\n    type BoxFuture<T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + Send>>;\n\n    #[derive(Debug, Clone)]\n    struct Svc;\n\n    impl<B> tower_service::Service<Request<B>> for Svc {\n        type Response = Response<Body>;\n        type Error = std::convert::Infallible;\n        type Future = BoxFuture<Self::Response, Self::Error>;\n\n        fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n\n        fn call(&mut self, _: Request<B>) -> Self::Future {\n            Box::pin(async { Ok(Response::new(Body::default())) })\n        }\n    }\n\n    impl NamedService for Svc {\n        const NAME: &'static str = \"test\";\n    }\n\n    fn enable<S>(service: S) -> tower_http::cors::Cors<GrpcWebService<S>>\n    where\n        S: Service<http::Request<Body>, Response = http::Response<Body>>,\n    {\n        tower_layer::Stack::new(\n            crate::GrpcWebLayer::new(),\n            tower_http::cors::CorsLayer::new(),\n        )\n        .layer(service)\n    }\n\n    mod grpc_web {\n        use super::*;\n        use tower_layer::Layer;\n\n        fn request() -> Request<Body> {\n            Request::builder()\n                .method(Method::POST)\n                .header(CONTENT_TYPE, GRPC_WEB)\n                .header(ORIGIN, \"http://example.com\")\n                .body(Body::default())\n                .unwrap()\n        }\n\n        #[tokio::test]\n        async fn default_cors_config() {\n            let mut svc = enable(Svc);\n            let res = svc.call(request()).await.unwrap();\n\n            assert_eq!(res.status(), StatusCode::OK);\n        }\n\n        #[tokio::test]\n        async fn web_layer() {\n            let mut svc = crate::GrpcWebLayer::new().layer(Svc);\n            let res = svc.call(request()).await.unwrap();\n\n            assert_eq!(res.status(), StatusCode::OK);\n        }\n\n        #[tokio::test]\n        async fn web_layer_with_axum() {\n            let mut svc = axum::routing::Router::new()\n                .route(\"/\", axum::routing::post_service(Svc))\n                .layer(crate::GrpcWebLayer::new());\n\n            let res = svc.call(request()).await.unwrap();\n\n            assert_eq!(res.status(), StatusCode::OK);\n        }\n\n        #[tokio::test]\n        async fn without_origin() {\n            let mut svc = enable(Svc);\n\n            let mut req = request();\n            req.headers_mut().remove(ORIGIN);\n\n            let res = svc.call(req).await.unwrap();\n\n            assert_eq!(res.status(), StatusCode::OK);\n        }\n\n        #[tokio::test]\n        async fn only_post_and_options_allowed() {\n            let mut svc = enable(Svc);\n\n            for method in &[\n                Method::GET,\n                Method::PUT,\n                Method::DELETE,\n                Method::HEAD,\n                Method::PATCH,\n            ] {\n                let mut req = request();\n                *req.method_mut() = method.clone();\n\n                let res = svc.call(req).await.unwrap();\n\n                assert_eq!(\n                    res.status(),\n                    StatusCode::METHOD_NOT_ALLOWED,\n                    \"{method} should not be allowed\"\n                );\n            }\n        }\n\n        #[tokio::test]\n        async fn grpc_web_content_types() {\n            let mut svc = enable(Svc);\n\n            for ct in &[GRPC_WEB_TEXT, GRPC_WEB_PROTO, GRPC_WEB_TEXT_PROTO, GRPC_WEB] {\n                let mut req = request();\n                req.headers_mut()\n                    .insert(CONTENT_TYPE, HeaderValue::from_static(ct));\n\n                let res = svc.call(req).await.unwrap();\n\n                assert_eq!(res.status(), StatusCode::OK);\n            }\n        }\n    }\n\n    mod options {\n        use super::*;\n\n        fn request() -> Request<Body> {\n            Request::builder()\n                .method(Method::OPTIONS)\n                .header(ORIGIN, \"http://example.com\")\n                .header(ACCESS_CONTROL_REQUEST_HEADERS, \"x-grpc-web\")\n                .header(ACCESS_CONTROL_REQUEST_METHOD, \"POST\")\n                .body(Body::default())\n                .unwrap()\n        }\n\n        #[tokio::test]\n        async fn valid_grpc_web_preflight() {\n            let mut svc = enable(Svc);\n            let res = svc.call(request()).await.unwrap();\n\n            assert_eq!(res.status(), StatusCode::OK);\n        }\n    }\n\n    mod grpc {\n        use super::*;\n\n        fn request() -> Request<Body> {\n            Request::builder()\n                .version(Version::HTTP_2)\n                .header(CONTENT_TYPE, GRPC_CONTENT_TYPE)\n                .body(Body::default())\n                .unwrap()\n        }\n\n        #[tokio::test]\n        async fn h2_is_ok() {\n            let mut svc = enable(Svc);\n\n            let req = request();\n            let res = svc.call(req).await.unwrap();\n\n            assert_eq!(res.status(), StatusCode::OK)\n        }\n\n        #[tokio::test]\n        async fn h1_is_err() {\n            let mut svc = enable(Svc);\n\n            let req = Request::builder()\n                .header(CONTENT_TYPE, GRPC_CONTENT_TYPE)\n                .body(Body::default())\n                .unwrap();\n\n            let res = svc.call(req).await.unwrap();\n            assert_eq!(res.status(), StatusCode::BAD_REQUEST)\n        }\n\n        #[tokio::test]\n        async fn content_type_variants() {\n            let mut svc = enable(Svc);\n\n            for variant in &[\"grpc\", \"grpc+proto\", \"grpc+thrift\", \"grpc+foo\"] {\n                let mut req = request();\n                req.headers_mut().insert(\n                    CONTENT_TYPE,\n                    HeaderValue::from_maybe_shared(format!(\"application/{variant}\")).unwrap(),\n                );\n\n                let res = svc.call(req).await.unwrap();\n\n                assert_eq!(res.status(), StatusCode::OK)\n            }\n        }\n    }\n\n    mod other {\n        use super::*;\n\n        fn request() -> Request<Body> {\n            Request::builder()\n                .header(CONTENT_TYPE, \"application/text\")\n                .body(Body::default())\n                .unwrap()\n        }\n\n        #[tokio::test]\n        async fn h1_is_err() {\n            let mut svc = enable(Svc);\n            let res = svc.call(request()).await.unwrap();\n\n            assert_eq!(res.status(), StatusCode::BAD_REQUEST)\n        }\n\n        #[tokio::test]\n        async fn h2_is_ok() {\n            let mut svc = enable(Svc);\n            let mut req = request();\n            *req.version_mut() = Version::HTTP_2;\n\n            let res = svc.call(req).await.unwrap();\n            assert_eq!(res.status(), StatusCode::OK)\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-xds/Cargo.toml",
    "content": "[package]\nname = \"tonic-xds\"\nversion = \"0.1.0-alpha.1\"\nedition = \"2024\"\nrust-version.workspace = true\nhomepage = \"https://github.com/hyperium/tonic\"\nrepository = \"https://github.com/hyperium/tonic\"\nauthors = [\n    \"Ankur Mittal <ankurmit2006@gmail.com>\",\n    \"Jeff Jiang <guokeno0@gmail.com>\",\n    \"Lucio Franco <luciofranco14@gmail.com>\",\n    \"Yutao Ma <ytma98@gmail.com>\"\n]\ncategories = [\"web-programming\", \"network-programming\", \"asynchronous\"]\ndescription = \"\"\"\nxDS routing and load balancing implementation for Tonic and Tower services\n\"\"\"\nkeywords = [\"grpc\", \"xds\"]\nlicense = \"MIT\"\npublish = false\nexclude = [\"proto/test/*\"]\n\n[dependencies]\ntonic = \"0.14\"\nhttp = \"1\"\ntower = { version = \"0.5\", default-features = false, features = [\"discover\"] }\ndashmap = \"6.1\"\nthiserror = \"2.0.17\"\nurl = \"2.5.8\"\nfutures-core = \"0.3.31\"\nbytes = \"1\"\nxds-client = { version = \"0.1.0-alpha.1\", path = \"../xds-client\" }\nserde = { version = \"1\", features = [\"derive\"] }\nserde_json = \"1\"\nenvoy-types = \"0.7\"\nprost = \"0.14\"\nregex = \"1\"\n\n[lints]\nworkspace = true\n\n[dev-dependencies]\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\", \"net\"] }\ntonic = { version = \"0.14\", features = [ \"server\", \"channel\", \"tls-ring\" ] }\ntonic-prost = \"0.14\"\ntokio-stream = \"0.1\"\ntonic-prost-build = \"0.14\"\n"
  },
  {
    "path": "tonic-xds/examples/gen_test_proto.rs",
    "content": "//! Build script for the protobufs used for tests.\n//! To invoke, run:\n//! ```\n//! cargo run -p tonic-xds --example gen_test_proto\n//! ```\nuse std::path::PathBuf;\nfn main() {\n    let manifest_dir = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"));\n    let proto_dir = manifest_dir.join(\"proto/test\");\n    let proto_file = proto_dir.join(\"helloworld.proto\");\n    let out_dir = manifest_dir.join(\"src/testutil/proto\");\n    println!(\"Writing generated test protos to {}\", out_dir.display());\n    tonic_prost_build::configure()\n        .out_dir(proto_dir.clone())\n        .compile_protos(\n            &[proto_file.to_str().unwrap()],\n            &[proto_dir.to_str().unwrap()],\n        )\n        .unwrap();\n}\n"
  },
  {
    "path": "tonic-xds/proto/test/helloworld.proto",
    "content": "// Copyright 2015 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"io.grpc.examples.helloworld\";\noption java_outer_classname = \"HelloWorldProto\";\n\npackage helloworld;\n\n// The greeting service definition.\nservice Greeter {\n  // Sends a greeting\n  rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n// The request message containing the user's name.\nmessage HelloRequest {\n  string name = 1;\n}\n\n// The response message containing the greetings\nmessage HelloReply {\n  string message = 1;\n}\n"
  },
  {
    "path": "tonic-xds/src/client/channel.rs",
    "content": "use crate::XdsUri;\nuse crate::client::endpoint::{EndpointAddress, EndpointChannel};\nuse crate::client::lb::XdsLbService;\nuse crate::client::route::XdsRoutingService;\nuse crate::common::async_util::BoxFuture;\nuse http::Request;\nuse std::fmt::Debug;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse tonic::{body::Body as TonicBody, client::GrpcService, transport::channel::Channel};\nuse tower::{BoxError, Service, load::Load, util::BoxCloneService};\n\n#[cfg(test)]\nuse {\n    crate::client::cluster::ClusterClientRegistryGrpc, crate::client::route::XdsRoutingLayer,\n    crate::xds::xds_manager::XdsManager, tower::ServiceBuilder,\n};\n\n/// Configuration for building [`XdsChannel`] / [`XdsChannelGrpc`].\n/// Currently, only support specifying the xDS URI for the target service.\n/// In the future, more configurations such as xDS management server address will be added.\n#[derive(Clone, Debug, Default)]\npub struct XdsChannelConfig {\n    target_uri: Option<XdsUri>,\n}\n\nimpl XdsChannelConfig {\n    /// Sets the xDS URI for the channel.\n    #[must_use]\n    pub fn with_target_uri(mut self, target_uri: XdsUri) -> Self {\n        self.target_uri = Some(target_uri);\n        self\n    }\n}\n\n/// `XdsChannel` is an xDS-capable [`tower::Service`] implementation.\n///\n/// It routes requests according to the xDS configuration that it fetches from the xDS management server.\n/// The routing implementation is based on the [Google gRPC xDS features](https://grpc.github.io/grpc/core/md_doc_grpc_xds_features.html).\n///\n/// # Type Parameters\n///\n/// * `Req` - The request type that this channel accepts, as an example: `http::Request<Body>`.\n/// * `Endpoint` - The endpoint identifier type used for load balancing (e.g., socket address).\n/// * `S` - The underlying [`tower::Service`] implementation that handles individual endpoint connections.\npub struct XdsChannel<Req, Endpoint, S>\nwhere\n    Req: Send + 'static,\n    S: Service<Req>,\n    S::Response: Send + 'static,\n{\n    config: Arc<XdsChannelConfig>,\n    // Currently the routing decision is directly executed by the XdsLbService.\n    // In the future, we will add more layers in between for retries, request mirroring, etc.\n    inner: XdsRoutingService<XdsLbService<Req, Endpoint, S>>,\n}\n\n#[allow(clippy::missing_fields_in_debug)]\nimpl<Req, Endpoint, S> Debug for XdsChannel<Req, Endpoint, S>\nwhere\n    Req: Send + 'static,\n    S: Service<Req>,\n    S::Response: Send + 'static,\n{\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"XdsChannel\")\n            .field(\"config\", &self.config)\n            .finish()\n    }\n}\n\nimpl<Req, Endpoint, S> Clone for XdsChannel<Req, Endpoint, S>\nwhere\n    Req: Send + 'static,\n    S: Service<Req>,\n    S::Response: Send + 'static,\n    XdsRoutingService<XdsLbService<Req, Endpoint, S>>: Clone,\n{\n    fn clone(&self) -> Self {\n        Self {\n            config: self.config.clone(),\n            inner: self.inner.clone(),\n        }\n    }\n}\n\nimpl<B, Endpoint, S> Service<http::Request<B>> for XdsChannel<Request<B>, Endpoint, S>\nwhere\n    B: Send + 'static,\n    Request<B>: Send + 'static,\n    Endpoint: std::hash::Hash + Eq + Clone + Send + 'static,\n    S: Service<Request<B>> + Load + Send + 'static,\n    S::Response: Send + 'static,\n    S::Error: Into<BoxError>,\n    S::Future: Send,\n    <S as tower::load::Load>::Metric: std::fmt::Debug,\n{\n    type Response = S::Response;\n    type Error = BoxError;\n    type Future = BoxFuture<Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, request: Request<B>) -> Self::Future {\n        self.inner.call(request)\n    }\n}\n\n/// A type alias for an `XdsChannel` that uses Tonic's Channel as the underlying transport.\npub(crate) type XdsChannelTonicGrpc =\n    XdsChannel<http::Request<TonicBody>, EndpointAddress, EndpointChannel<Channel>>;\n\n/// A [`tonic::client::GrpcService`] implementation that can route and load-balance\n/// gRPC requests based on xDS configuration.\npub type XdsChannelGrpc =\n    BoxCloneService<http::Request<TonicBody>, http::Response<TonicBody>, BoxError>;\n\n// Static assertion that XdsChannelGrpc and XdsChannelTonicGrpc implement GrpcService\nconst _: fn() = || {\n    fn assert_grpc_service<T: GrpcService<TonicBody>>() {}\n    assert_grpc_service::<XdsChannelGrpc>();\n    assert_grpc_service::<XdsChannelTonicGrpc>();\n};\n\n/// Builder for creating an [`XdsChannel`] or [`XdsChannelGrpc`].\n#[derive(Clone, Debug)]\npub struct XdsChannelBuilder {\n    #[allow(dead_code)]\n    config: Arc<XdsChannelConfig>,\n}\n\nimpl XdsChannelBuilder {\n    /// Create a builder from an channel configurations.\n    #[must_use]\n    pub fn with_config(config: XdsChannelConfig) -> Self {\n        Self {\n            config: Arc::new(config),\n        }\n    }\n\n    /// Builds an `XdsChannel`, which takes generic request, endpoint, and service types and can be\n    /// used for generic HTTP services.\n    #[must_use]\n    pub fn build_channel<Req, Endpoint, S>(&self) -> XdsChannel<Req, Endpoint, S>\n    where\n        Req: Send + 'static,\n        S: Service<Req>,\n        S::Response: Send + 'static,\n    {\n        todo!(\"Implement XdsChannel building logic\");\n    }\n\n    pub(crate) fn build_tonic_grpc_channel(&self) -> XdsChannelTonicGrpc {\n        todo!(\"Implement XdsChannel building logic\");\n    }\n\n    /// Builds an `XdsChannelGrpc`, which is a type-erased gRPC channel.\n    #[must_use]\n    pub fn build_grpc_channel(&self) -> XdsChannelGrpc {\n        BoxCloneService::new(self.build_tonic_grpc_channel())\n    }\n\n    /// Builds an `XdsChannelGrpc` from the given xDS manager dependencies.\n    /// This is primarily intended for testing purposes for now.\n    /// [`XdsChannelBuilder::build_grpc_channel`] should build [`XdsManager`](crate::xds::xds_manager::XdsManager)\n    /// as part of constructing `XdsChannelGrpc`.\n    #[cfg(test)]\n    pub(crate) fn build_grpc_channel_from_xds_manager(\n        &self,\n        xds_manager: Arc<dyn XdsManager<EndpointAddress, EndpointChannel<Channel>>>,\n    ) -> XdsChannelGrpc {\n        let routing_layer = XdsRoutingLayer::new(xds_manager.clone());\n        let cluster_registry = Arc::new(ClusterClientRegistryGrpc::new());\n        let lb_service = XdsLbService::new(cluster_registry, xds_manager.clone());\n        let service = ServiceBuilder::new()\n            .layer(routing_layer)\n            .service(lb_service);\n        BoxCloneService::new(XdsChannelTonicGrpc {\n            config: self.config.clone(),\n            inner: service,\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::XdsChannelBuilder;\n    use super::XdsChannelConfig;\n    use crate::client::channel::XdsChannelGrpc;\n    use crate::client::endpoint::EndpointAddress;\n    use crate::client::endpoint::EndpointChannel;\n    use crate::client::route::RouteDecision;\n    use crate::client::route::RouteInput;\n    use crate::common::async_util::BoxFuture;\n    use crate::testutil::grpc::GreeterClient;\n    use crate::testutil::grpc::HelloRequest;\n    use crate::testutil::grpc::TestServer;\n    use crate::xds::xds_manager::BoxDiscover;\n    use crate::xds::xds_manager::{XdsClusterDiscovery, XdsRouter};\n    use std::sync::Arc;\n    use tokio::sync::mpsc;\n    use tonic::transport::Channel;\n    use tower::discover::Change;\n\n    /// Sets up multiple gRPC test servers and returns their addresses, clients and shutdown handles.\n    async fn setup_grpc_servers(\n        count: usize,\n    ) -> (Vec<String>, Vec<crate::testutil::grpc::TestServer>) {\n        use crate::testutil::grpc::spawn_greeter_server;\n\n        let mut servers = Vec::new();\n        let mut server_addrs = Vec::new();\n\n        for i in 0..count {\n            let server_name = format!(\"server-{i}\");\n            let server = spawn_greeter_server(&server_name, None, None)\n                .await\n                .expect(\"Failed to spawn gRPC server\");\n\n            server_addrs.push(server.addr.to_string());\n            servers.push(server);\n        }\n\n        (server_addrs, servers)\n    }\n\n    /// A mock XdsManager that provides pre-configured endpoints for testing.\n    struct MockXdsManager {\n        endpoints: Vec<(EndpointAddress, Channel)>,\n    }\n\n    impl MockXdsManager {\n        /// Creates a new MockXdsManager from test servers.\n        fn from_test_servers(servers: &[TestServer]) -> Self {\n            let endpoints = servers\n                .iter()\n                .map(|s| {\n                    let addr = EndpointAddress::from(s.addr);\n                    (addr, s.channel.clone())\n                })\n                .collect();\n            Self { endpoints }\n        }\n    }\n\n    impl XdsRouter for MockXdsManager {\n        fn route(&self, _input: &RouteInput<'_>) -> BoxFuture<RouteDecision> {\n            Box::pin(async move {\n                RouteDecision {\n                    cluster: \"test-cluster\".to_string(),\n                }\n            })\n        }\n    }\n\n    impl XdsClusterDiscovery<EndpointAddress, EndpointChannel<Channel>> for MockXdsManager {\n        fn discover_cluster(\n            &self,\n            _cluster_name: &str,\n        ) -> BoxDiscover<EndpointAddress, EndpointChannel<Channel>> {\n            let endpoints = self.endpoints.clone();\n            let (tx, rx) = mpsc::channel(16);\n\n            tokio::spawn(async move {\n                for (addr, channel) in endpoints {\n                    let endpoint_channel = EndpointChannel::new(channel);\n                    let change = Change::Insert(addr, endpoint_channel);\n                    tx.send(Ok(change)).await.expect(\"Failed to send SD change\");\n                }\n            });\n\n            Box::pin(tokio_stream::wrappers::ReceiverStream::new(rx))\n        }\n    }\n\n    /// Sends multiple gRPC requests using the provided client and returns statistics about the requests.\n    async fn send_grpc_requests(\n        mut grpc_client: crate::testutil::grpc::GreeterClient<XdsChannelGrpc>,\n        num_requests: usize,\n    ) -> (\n        usize,\n        std::collections::HashMap<String, usize>,\n        std::collections::HashMap<String, usize>,\n    ) {\n        let mut successful_requests = 0;\n        let mut error_types = std::collections::HashMap::new();\n        let mut server_counts = std::collections::HashMap::new();\n\n        for i in 0..num_requests {\n            let request_timeout = tokio::time::Duration::from_secs(3);\n            let request_future = grpc_client.say_hello(HelloRequest {\n                name: format!(\"test-request-{i}\"),\n            });\n\n            match tokio::time::timeout(request_timeout, request_future).await {\n                Ok(Ok(response)) => {\n                    successful_requests += 1;\n                    // Extract server name from response message (format: \"server-X: test-request-Y\")\n                    let message = response.into_inner().message;\n                    if let Some(server_name) = message.split(':').next() {\n                        *server_counts.entry(server_name.to_string()).or_insert(0) += 1;\n                    }\n                }\n                Ok(Err(e)) => {\n                    let error_type = format!(\"{e:?}\").chars().take(80).collect::<String>();\n                    *error_types.entry(error_type).or_insert(0) += 1;\n                }\n                Err(_) => {\n                    *error_types.entry(\"Timeout\".to_string()).or_insert(0) += 1;\n                    if error_types.get(\"Timeout\").unwrap_or(&0) > &2 {\n                        break;\n                    }\n                }\n            }\n        }\n\n        (successful_requests, error_types, server_counts)\n    }\n\n    #[tokio::test]\n    /// Tests the `XdsChannelGrpc` with a power-of-two-choices load balancer.\n    async fn test_xds_channel_grpc_with_p2c_lb() {\n        let num_requests = 1000;\n        let num_servers = 5;\n        let (_, servers) = setup_grpc_servers(num_servers).await;\n\n        // Create a mock XdsManager with the test servers\n        let xds_manager = Arc::new(MockXdsManager::from_test_servers(&servers));\n\n        let xds_channel_builder = XdsChannelBuilder::with_config(XdsChannelConfig::default());\n        let xds_channel =\n            xds_channel_builder.build_grpc_channel_from_xds_manager(xds_manager.clone());\n\n        let client = GreeterClient::new(xds_channel);\n\n        let (successful_requests, error_types, server_counts) =\n            send_grpc_requests(client, num_requests).await;\n\n        println!(\"Successful requests: {successful_requests}\");\n        println!(\"Error types: {error_types:?}\");\n        println!(\"Per-server call counts: {server_counts:?}\");\n\n        assert_eq!(\n            successful_requests, num_requests,\n            \"Expected 100% success rate. Got {successful_requests} successful out of {num_requests} requests. Errors: {error_types:?}\",\n        );\n\n        assert!(\n            error_types.is_empty(),\n            \"Expected no errors but got: {error_types:?}\",\n        );\n\n        let actual_server_count = server_counts.len();\n        assert_eq!(\n            actual_server_count, num_servers,\n            \"Expected all {num_servers} servers to receive requests, but only {actual_server_count} servers received traffic. Server counts: {server_counts:?}\",\n        );\n\n        let expected_per_server = num_requests / num_servers;\n        let min_requests_per_server = (expected_per_server as f64 / 1.5) as usize;\n        let max_requests_per_server = (expected_per_server as f64 * 1.5) as usize;\n\n        for (server_name, count) in &server_counts {\n            assert!(\n                *count >= min_requests_per_server,\n                \"Server {server_name} received only {count} requests, expected at least {min_requests_per_server} (expected ~{expected_per_server} per server with 1.5x variance)\",\n            );\n            assert!(\n                *count <= max_requests_per_server,\n                \"Server {server_name} received {count} requests, expected at most {max_requests_per_server} (expected ~{expected_per_server} per server with 1.5x variance)\",\n            );\n        }\n\n        let total_server_requests: usize = server_counts.values().sum();\n        assert_eq!(\n            total_server_requests, successful_requests,\n            \"Total server requests ({total_server_requests}) should equal successful requests ({successful_requests}). Server counts: {server_counts:?}\",\n        );\n\n        for server in servers {\n            let _ = server.shutdown.send(());\n            let _ = server.handle.await;\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/client/cluster.rs",
    "content": "use crate::common::async_util::BoxFuture;\nuse dashmap::DashMap;\nuse http::{Request, Response};\nuse std::fmt::Debug;\nuse std::future::Future;\nuse std::hash::Hash;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse tonic::body::Body as TonicBody;\nuse tower::{\n    BoxError, Service, balance::p2c::Balance, buffer::Buffer, discover::Discover, load::Load,\n};\n\ntype RespFut<Resp> = BoxFuture<Result<Resp, BoxError>>;\n\nconst DEFAULT_BUFFER_CAPACITY: usize = 1024;\n\n/// `ClusterBalancer` is responsible for managing load balancing requests across multiple channels.\n/// Currently, `ClusterBalancer` leverges `tower::balance::p2c` for doing P2C load balancing. In the future, we will\n/// support more load balancing strategies as needed.\npub(crate) struct ClusterBalancer<D, Req>\nwhere\n    D: Discover,\n    D::Key: Hash,\n{\n    balancer: Balance<D, Req>,\n}\n\nimpl<D, Req> ClusterBalancer<D, Req>\nwhere\n    D: Discover,\n    D::Key: Hash,\n    D::Service: Service<Req>,\n    <D::Service as Service<Req>>::Error: Into<BoxError>,\n{\n    /// Creates a new `ClusterBalancer` with provided service discovery.\n    pub(crate) fn new(discover: D) -> Self {\n        Self {\n            balancer: Balance::new(discover),\n        }\n    }\n\n    /// Returns the number of endpoints currently tracked by the balancer.\n    /// This can be useful for monitoring and debugging purposes.\n    #[allow(dead_code)]\n    pub(crate) fn len(&self) -> usize {\n        self.balancer.len()\n    }\n}\n\nimpl<D, Req> Service<Req> for ClusterBalancer<D, Req>\nwhere\n    D: Discover + Unpin,\n    D::Key: Hash + Clone,\n    D::Error: Into<BoxError>,\n    D::Service: Service<Req> + Load,\n    <D::Service as Load>::Metric: std::fmt::Debug,\n    <D::Service as Service<Req>>::Error: Into<BoxError> + 'static,\n    <D::Service as Service<Req>>::Future: Send + 'static,\n{\n    type Response = <Balance<D, Req> as Service<Req>>::Response;\n    type Error = <Balance<D, Req> as Service<Req>>::Error;\n    type Future = RespFut<Self::Response>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.balancer.poll_ready(cx)\n    }\n\n    fn call(&mut self, req: Req) -> Self::Future {\n        Box::pin(self.balancer.call(req))\n    }\n}\n\n/// `ClusterChannel` is similar to `tonic::transport::Channel`, but is for load-balancing across all\n/// the channels for a xDS Cluster.\n/// `ClusterChannel` should be cloned to be used in multi-threaded environment. It leverages a `tower::Buffer` to\n/// queue requests from multiple callers and behind the queue, it load-balances the requests across all\n/// available channels by leveraging the inner `ClusterBalancer` object.\npub(crate) struct ClusterChannel<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    // The mpsc channel between callers and the actual pool of channels.\n    svc: Buffer<Req, BoxFuture<Result<Resp, BoxError>>>,\n}\n\nimpl<Req, Resp> Clone for ClusterChannel<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    fn clone(&self) -> Self {\n        Self {\n            svc: self.svc.clone(),\n        }\n    }\n}\n\nimpl<Req, Resp> ClusterChannel<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    /// Creates a new `ClusterChannel` with the given service and picker.\n    pub(crate) fn from_balancer<B>(balancer: B, buffer_cap: usize) -> Self\n    where\n        B: Service<Req, Error = BoxError, Future = RespFut<Resp>> + Send + 'static,\n    {\n        let svc = Buffer::new(balancer, buffer_cap);\n        Self { svc }\n    }\n}\n\nimpl<Req, Resp> Service<Req> for ClusterChannel<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    type Response = Resp;\n    type Error = BoxError;\n    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Service::poll_ready(&mut self.svc, cx).map_err(BoxError::from)\n    }\n\n    fn call(&mut self, request: Req) -> Self::Future {\n        Box::pin(self.svc.call(request))\n    }\n}\n\n/// `ClusterClient` manages channels that load-balance for a xDS cluster.\npub(crate) struct ClusterClient<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    name: String,\n    channel: ClusterChannel<Req, Resp>,\n}\n\nimpl Debug for ClusterClient<(), ()> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"ClusterClient\")\n            .field(\"name\", &self.name)\n            .finish()\n    }\n}\n\nimpl<Req, Resp> ClusterClient<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    /// Creates a new `ClusterClient` with the given cluster name and service discovery implementation.\n    /// Currently, `tower::discover::Discover` is used for service discovery.\n    pub(crate) fn new<D>(name: String, discover: D) -> Self\n    where\n        D: Discover + Unpin + Send + 'static,\n        D::Key: std::hash::Hash + Clone + Send,\n        D::Error: Into<BoxError>,\n        D::Service: Service<Req, Response = Resp> + Load + Send + 'static,\n        <D::Service as Load>::Metric: std::fmt::Debug,\n        <D::Service as Service<Req>>::Error: Into<BoxError>,\n        <D::Service as Service<Req>>::Future: Send + 'static,\n    {\n        let balancer = ClusterBalancer::new(discover);\n        let channel = ClusterChannel::from_balancer(balancer, DEFAULT_BUFFER_CAPACITY);\n        Self { name, channel }\n    }\n\n    /// Returns a channel that can be used to send RPCs to the cluster.\n    pub(crate) fn channel(&self) -> ClusterChannel<Req, Resp> {\n        self.channel.clone()\n    }\n\n    /// Returns the name of the cluster.\n    #[allow(dead_code)]\n    pub(crate) fn name(&self) -> &str {\n        &self.name\n    }\n}\n\n/// `ClusterRegistry` is the client registry for all xDS clusters.\n/// The xDS Tower service implementations uses this to get the client for a specific cluster.\npub(crate) struct ClusterClientRegistry<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    registry: DashMap<String, Arc<ClusterClient<Req, Resp>>>,\n}\n\nimpl<Req, Resp> ClusterClientRegistry<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    /// Creates a new `ClusterClientRegistry`.\n    pub(crate) fn new() -> Self {\n        Self {\n            registry: DashMap::new(),\n        }\n    }\n    /// Get the client of a cluster with lazy discovery.\n    pub(crate) fn get_cluster<F, D>(\n        &self,\n        key: &str,\n        discover_fn: F,\n    ) -> Arc<ClusterClient<Req, Resp>>\n    where\n        F: FnOnce() -> D,\n        D: Discover + Unpin + Send + 'static,\n        D::Key: std::hash::Hash + Clone + Send,\n        D::Error: Into<BoxError>,\n        D::Service: Service<Req, Response = Resp> + Load + Send + 'static,\n        <D::Service as Load>::Metric: std::fmt::Debug,\n        <D::Service as Service<Req>>::Error: Into<BoxError>,\n        <D::Service as Service<Req>>::Future: Send + 'static,\n    {\n        self.registry\n            .entry(key.to_string())\n            .or_insert_with(|| {\n                let name = key.to_string();\n                let discover = discover_fn();\n                Arc::new(ClusterClient::new(name, discover))\n            })\n            .clone()\n    }\n}\n\nimpl<Req, Resp> Default for ClusterClientRegistry<Req, Resp>\nwhere\n    Req: Send + 'static,\n    Resp: 'static,\n{\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// A type erased registry for Tonic clients.\n/// This will be used by the xDS Tower Service implementations to get the client for a specific Tonic xDS cluster.\n#[allow(dead_code)]\npub(crate) type ClusterClientRegistryGrpc =\n    ClusterClientRegistry<Request<TonicBody>, Response<TonicBody>>;\n"
  },
  {
    "path": "tonic-xds/src/client/endpoint.rs",
    "content": "use crate::common::async_util::BoxFuture;\nuse std::net::SocketAddr;\nuse std::sync::{Arc, atomic::AtomicU64, atomic::Ordering};\nuse std::task::{Context, Poll};\nuse tower::{Service, load::Load};\n\n/// Represents the host part of an endpoint address\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\nenum EndpointHost {\n    Ipv4(std::net::Ipv4Addr),\n    Ipv6(std::net::Ipv6Addr),\n    Hostname(String),\n}\n\nimpl From<String> for EndpointHost {\n    fn from(s: String) -> Self {\n        if let Ok(ipv4) = s.parse::<std::net::Ipv4Addr>() {\n            EndpointHost::Ipv4(ipv4)\n        } else if let Ok(ipv6) = s.parse::<std::net::Ipv6Addr>() {\n            EndpointHost::Ipv6(ipv6)\n        } else {\n            EndpointHost::Hostname(s)\n        }\n    }\n}\n\n/// Represents a validated endpoint address extracted from xDS\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\npub(crate) struct EndpointAddress {\n    /// The IP address or hostname\n    host: EndpointHost,\n    /// The port number\n    port: u16,\n}\n\nimpl EndpointAddress {\n    /// Creates a new `EndpointAddress` from a host string and port.\n    ///\n    /// Attempts to parse the host as an IP address; falls back to hostname.\n    #[allow(dead_code)]\n    pub(crate) fn new(host: impl Into<String>, port: u16) -> Self {\n        Self {\n            host: EndpointHost::from(host.into()),\n            port,\n        }\n    }\n}\n\nimpl std::fmt::Display for EndpointAddress {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match &self.host {\n            EndpointHost::Ipv4(ip) => write!(f, \"{ip}:{}\", self.port),\n            EndpointHost::Ipv6(ip) => write!(f, \"[{ip}]:{}\", self.port),\n            EndpointHost::Hostname(h) => write!(f, \"{h}:{}\", self.port),\n        }\n    }\n}\n\nimpl From<SocketAddr> for EndpointAddress {\n    fn from(addr: SocketAddr) -> Self {\n        match addr {\n            SocketAddr::V4(v4_addr) => Self {\n                host: EndpointHost::Ipv4(*v4_addr.ip()),\n                port: v4_addr.port(),\n            },\n            SocketAddr::V6(v6_addr) => Self {\n                host: EndpointHost::Ipv6(*v6_addr.ip()),\n                port: v6_addr.port(),\n            },\n        }\n    }\n}\n\n/// RAII tracker for in-flight requests.\n/// This is mainly used to implement endpoint load reporting for load balancing purposes.\n#[derive(Clone, Debug, Default)]\nstruct InFlightTracker {\n    in_flight: Arc<AtomicU64>,\n}\n\nimpl InFlightTracker {\n    fn new(in_flight: Arc<AtomicU64>) -> Self {\n        in_flight.fetch_add(1, Ordering::Relaxed);\n        Self { in_flight }\n    }\n}\n\nimpl Drop for InFlightTracker {\n    fn drop(&mut self) {\n        self.in_flight.fetch_sub(1, Ordering::Relaxed);\n    }\n}\n\n/// An endpoint channel for communicating with a single gRPC endpoint, with load reporting support for load balancing.\npub(crate) struct EndpointChannel<S> {\n    inner: S,\n    in_flight: Arc<AtomicU64>,\n}\n\nimpl<S> EndpointChannel<S> {\n    /// Creates a new `EndpointChannel`.\n    /// This should be used by xDS implementations to construct channels to individual endpoints.\n    #[allow(dead_code)]\n    pub(crate) fn new(inner: S) -> Self {\n        Self {\n            inner,\n            in_flight: Arc::new(AtomicU64::new(0)),\n        }\n    }\n}\n\nimpl<S> Clone for EndpointChannel<S>\nwhere\n    S: Clone,\n{\n    fn clone(&self) -> Self {\n        Self {\n            inner: self.inner.clone(),\n            in_flight: self.in_flight.clone(),\n        }\n    }\n}\n\nimpl<S, Req> Service<Req> for EndpointChannel<S>\nwhere\n    S: Service<Req> + Send + 'static,\n    S::Future: Send + 'static,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = BoxFuture<Result<S::Response, S::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, req: Req) -> Self::Future {\n        let in_flight = InFlightTracker::new(self.in_flight.clone());\n        let fut = self.inner.call(req);\n\n        // -1 when the inner future completes\n        Box::pin(async move {\n            let _in_flight_guard = in_flight;\n\n            fut.await\n        })\n    }\n}\n\nimpl<S> Load for EndpointChannel<S> {\n    type Metric = u64;\n    fn load(&self) -> Self::Metric {\n        self.in_flight.load(Ordering::Relaxed)\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/client/lb.rs",
    "content": "use crate::client::cluster::ClusterClientRegistry;\nuse crate::client::route::RouteDecision;\nuse crate::common::async_util::BoxFuture;\nuse crate::xds::xds_manager::XdsClusterDiscovery;\nuse http::Request;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse tower::ServiceExt;\nuse tower::{BoxError, Service, load::Load};\n\n/// Errors that can occur during load balancing.\n#[derive(Debug, Clone, thiserror::Error)]\npub(crate) enum LoadBalancingError {\n    #[error(\"No routing decision extension from the routing layer available\")]\n    NoRoutingDecision,\n}\n\n/// A Tower Service that performs load balancing based on routing decisions and xDS configuration.\npub(crate) struct XdsLbService<Req, Endpoint, S>\nwhere\n    Req: Send + 'static,\n    S: Service<Req>,\n    S::Response: Send + 'static,\n{\n    cluster_registry: Arc<ClusterClientRegistry<Req, S::Response>>,\n    cluster_discovery: Arc<dyn XdsClusterDiscovery<Endpoint, S>>,\n}\n\nimpl<Req, Endpoint, S> XdsLbService<Req, Endpoint, S>\nwhere\n    Req: Send + 'static,\n    S: Service<Req>,\n    S::Response: Send + 'static,\n{\n    /// Creates a new `XdsLbService` with the given cluster client registry and xDS cluster discovery.\n    #[allow(dead_code)]\n    pub(crate) fn new(\n        cluster_registry: Arc<ClusterClientRegistry<Req, S::Response>>,\n        cluster_discovery: Arc<dyn XdsClusterDiscovery<Endpoint, S>>,\n    ) -> Self {\n        Self {\n            cluster_registry,\n            cluster_discovery,\n        }\n    }\n}\n\nimpl<Req, Endpoint, S> Clone for XdsLbService<Req, Endpoint, S>\nwhere\n    Req: Send + 'static,\n    S: Service<Req>,\n    S::Response: Send + 'static,\n{\n    fn clone(&self) -> Self {\n        Self {\n            cluster_registry: self.cluster_registry.clone(),\n            cluster_discovery: self.cluster_discovery.clone(),\n        }\n    }\n}\n\nimpl<B, Endpoint, S> Service<Request<B>> for XdsLbService<Request<B>, Endpoint, S>\nwhere\n    Request<B>: Send + 'static,\n    S::Response: Send + 'static,\n    Endpoint: std::hash::Hash + Eq + Clone + Send + 'static,\n    S: Service<Request<B>> + Load + Send + 'static,\n    S::Response: Send + 'static,\n    S::Error: Into<BoxError>,\n    S::Future: Send,\n    <S as tower::load::Load>::Metric: std::fmt::Debug,\n{\n    type Response = S::Response;\n    type Error = BoxError;\n    type Future = BoxFuture<Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        // Under xDS, the destination cluster is decided by the routing layer, which takes\n        // the request as an input. Therefore, we cannot determine readiness without\n        // knowing the target cluster, which is tied to the request.\n        Poll::Ready(Ok(()))\n    }\n\n    fn call(&mut self, request: Request<B>) -> Self::Future {\n        // Extract the routing decision from the request extensions.\n        let Some(routing_decision) = request.extensions().get::<RouteDecision>().cloned() else {\n            return Box::pin(async move { Err(LoadBalancingError::NoRoutingDecision.into()) });\n        };\n\n        // Get or create the cluster client for the target xDS cluster.\n        let cluster_client = self\n            .cluster_registry\n            .get_cluster(&routing_decision.cluster, || {\n                self.cluster_discovery\n                    .discover_cluster(&routing_decision.cluster)\n            });\n\n        // Get the transport channel for the target xDS cluster.\n        // The actual load-balancing will be performeed by the channel.\n        let mut channel = cluster_client.channel();\n\n        Box::pin(async move {\n            // This will block until the first endpoint is available.\n            channel.ready().await?;\n            channel.call(request).await\n        })\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/client/mod.rs",
    "content": "pub(crate) mod channel;\npub(crate) mod cluster;\npub(crate) mod endpoint;\npub(crate) mod lb;\npub(crate) mod route;\n"
  },
  {
    "path": "tonic-xds/src/client/route.rs",
    "content": "use crate::common::async_util::BoxFuture;\nuse crate::xds::xds_manager::XdsRouter;\nuse http::Request;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse tower::{Layer, Service};\n\n/// Represents the input for xDS routing decisions.\n#[allow(dead_code)]\npub(crate) struct RouteInput<'a> {\n    /// The authority (host) of the request URI.\n    pub authority: &'a str,\n    /// The HTTP headers of the request. These can be used for header-based routing decisions.\n    pub headers: &'a http::HeaderMap,\n}\n\n/// Represents the routing decision made by the xDS routing layer.\n#[derive(Clone)]\npub(crate) struct RouteDecision {\n    /// The name of the cluster to which the request should be routed.\n    pub cluster: String,\n}\n\n/// Tower service for routing requests to the appropriate cluster based on the xDS routing configurations.\n/// Attaches routing decision as `RoutingDecision` to the request extensions.\n/// The `RoutingDecision` will be used by the `XdsLbService` to identify the xDS cluster to which the request should be routed.\n#[derive(Clone)]\npub(crate) struct XdsRoutingService<S> {\n    /// The inner Tower service to which the request will be forwarded after routing decision is made.\n    inner: S,\n    /// The xDS router used to make routing decisions based on the request and the xDS routing configurations.\n    xds_router: Arc<dyn XdsRouter>,\n}\n\nimpl<S, B> Service<Request<B>> for XdsRoutingService<S>\nwhere\n    S: Service<Request<B>> + Clone + Send + 'static,\n    B: Send + 'static,\n    S::Future: Send + 'static,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = BoxFuture<Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, mut request: Request<B>) -> Self::Future {\n        let xds_router = self.xds_router.clone();\n        let mut inner_service = self.inner.clone();\n        Box::pin(async move {\n            let authority = request\n                .uri()\n                .authority()\n                .map_or(\"\", http::uri::Authority::as_str);\n            let headers = &request.headers();\n            let route_input = RouteInput { authority, headers };\n            let route_decision = xds_router.route(&route_input).await;\n            request.extensions_mut().insert(route_decision);\n            inner_service.call(request).await\n        })\n    }\n}\n\n/// Tower layer for routing requests to the appropriate cluster based on the `RouteConfiguration`.\n#[derive(Clone)]\n#[allow(dead_code)]\npub(crate) struct XdsRoutingLayer {\n    xds_router: Arc<dyn XdsRouter>,\n}\n\nimpl XdsRoutingLayer {\n    /// Creates a new `XdsRoutingLayer` with the given `XdsRouter`.\n    #[allow(dead_code)]\n    pub(crate) fn new(xds_router: Arc<dyn XdsRouter>) -> Self {\n        Self { xds_router }\n    }\n}\n\nimpl<S> Layer<S> for XdsRoutingLayer {\n    type Service = XdsRoutingService<S>;\n\n    fn layer(&self, service: S) -> Self::Service {\n        XdsRoutingService {\n            inner: service,\n            xds_router: self.xds_router.clone(),\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/common/async_util.rs",
    "content": "//! Utilities for async operations.\n\nuse std::future::Future;\nuse std::pin::Pin;\n\npub(crate) type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;\n"
  },
  {
    "path": "tonic-xds/src/common/mod.rs",
    "content": "pub(crate) mod async_util;\n"
  },
  {
    "path": "tonic-xds/src/lib.rs",
    "content": "//! # tonic-xds\n//!\n//! xDS (discovery service) support for [Tonic](https://docs.rs/tonic) gRPC clients as well as\n//! general [`tower::Service`].\n//!\n//! This crate provides an xDS-enabled [`tonic::client::GrpcService`] implementation ([`XdsChannelGrpc`])\n//! that automatically discovers, routes and load-balances across endpoints using the xDS protocol.\n//! The implementation will align with the\n//! [gRPC xDS features](https://github.com/grpc/grpc/blob/master/doc/grpc_xds_features.md).\n//!\n//! In addition to gRPC, this crate also provides a generic [`tower::Service`] implementation ([`XdsChannel`])\n//! for enabling xDS features for generic Http clients. This can be used to support both gRPC and Http\n//! clients by the same xDS management server.\n//!\n//! ## Current Planned Features:\n//!\n//! - LDS / RDS / CDS / EDS subscriptions via ADS stream.\n//! - Client-side P2C load balancing\n//! - Other features will be added in future releases.\n//!\n//! ## Example\n//!\n//! ```rust,no_run\n//! use tonic_xds::{XdsChannelBuilder, XdsChannelConfig, XdsChannelGrpc, XdsUri};\n//!\n//! let target_uri = XdsUri::parse(\n//!   \"xds:///myservice:50051\"\n//! ).expect(\"fail to parse valid target URI\");\n//!\n//! let xds_channel = XdsChannelBuilder::with_config(\n//!   XdsChannelConfig::default().with_target_uri(target_uri)\n//! ).build_grpc_channel();\n//!\n//! // Use with your generated gRPC client\n//! // let client = MyServiceClient::new(xds_channel);\n//! // client.my_rpc_method(...).await;\n//! ```\n//!\n//! ## How it works\n//!\n//! [`XdsChannelGrpc`] connects to an xDS management server and subscribes to resource updates for\n//! listeners, routes, clusters, and endpoints. Requests are automatically routed and load-balanced\n//! in stacked [`tower::Service`]s that implement the [gRPC xDS features](https://github.com/grpc/grpc/blob/master/doc/grpc_xds_features.md).\n\npub(crate) mod client;\npub(crate) mod common;\npub(crate) mod xds;\n\npub use client::channel::{XdsChannel, XdsChannelBuilder, XdsChannelConfig, XdsChannelGrpc};\npub use xds::uri::{XdsUri, XdsUriError};\n\n#[cfg(test)]\npub(crate) mod testutil;\n"
  },
  {
    "path": "tonic-xds/src/testutil/grpc.rs",
    "content": "//! Test utilities for gRPC servers and clients.\nuse std::error::Error;\nuse std::net::SocketAddr;\nuse tokio::{net::TcpListener, sync::oneshot};\nuse tonic::server::NamedService;\nuse tonic::transport::{Channel, ClientTlsConfig, Endpoint, Server, ServerTlsConfig};\nuse tonic::{Request, Response, Status};\n\npub(crate) use crate::testutil::proto::helloworld::{\n    HelloReply, HelloRequest,\n    greeter_client::GreeterClient,\n    greeter_server::{Greeter, GreeterServer},\n};\n\n#[derive(Default)]\nstruct MyGreeter {\n    msg: String,\n}\n\n#[tonic::async_trait]\nimpl Greeter for MyGreeter {\n    async fn say_hello(&self, req: Request<HelloRequest>) -> Result<Response<HelloReply>, Status> {\n        Ok(Response::new(HelloReply {\n            message: format!(\"{}: {}\", self.msg, req.into_inner().name),\n        }))\n    }\n}\n\n/// A test server that runs a gRPC service and provides a channel for clients to connect.\npub(crate) struct TestServer {\n    /// The gRPC channel for talking to the test server.\n    pub channel: Channel,\n    /// Signal the server to shutdown.\n    pub shutdown: oneshot::Sender<()>,\n    /// Handle to wait for server to exit.\n    pub handle: tokio::task::JoinHandle<Result<(), tonic::transport::Error>>,\n    /// Server address.\n    pub addr: SocketAddr,\n}\n\nimpl NamedService for TestServer {\n    const NAME: &'static str = \"TestServer\";\n}\n\n/// Spawns a gRPC greeter server for testing purposes.\npub(crate) async fn spawn_greeter_server(\n    msg: &str,\n    server_tls: Option<ServerTlsConfig>,\n    client_tls: Option<ClientTlsConfig>,\n) -> Result<TestServer, Box<dyn Error>> {\n    // Bind to an ephemeral port (random free port assigned by OS)\n    let listener = TcpListener::bind(\"127.0.0.1:0\").await?;\n    let addr = listener.local_addr()?;\n    let incoming = tokio_stream::wrappers::TcpListenerStream::new(listener);\n\n    let (tx, rx) = oneshot::channel();\n\n    let svc = GreeterServer::new(MyGreeter {\n        msg: msg.to_string(),\n    });\n\n    let handle = tokio::spawn(async move {\n        let mut builder = if let Some(tls) = server_tls {\n            Server::builder().tls_config(tls)?\n        } else {\n            Server::builder()\n        };\n        let res = builder\n            .add_service(svc)\n            .serve_with_incoming_shutdown(incoming, async {\n                let _ = rx.await;\n            })\n            .await;\n        match res {\n            Ok(_) => println!(\"Server exited cleanly\"),\n            Err(e) => eprintln!(\"Server error: {e}\"),\n        }\n\n        Ok(())\n    });\n\n    let channel = if let Some(client_tls) = client_tls {\n        let endpoint_str = format!(\"https://{addr}\");\n        Endpoint::from_shared(endpoint_str)?\n            .tls_config(client_tls)?\n            .connect()\n            .await?\n    } else {\n        let endpoint_str = format!(\"http://{addr}\");\n        Endpoint::from_shared(endpoint_str)?.connect().await?\n    };\n\n    Ok(TestServer {\n        channel,\n        shutdown: tx,\n        handle,\n        addr,\n    })\n}\n"
  },
  {
    "path": "tonic-xds/src/testutil/mod.rs",
    "content": "#[cfg(test)]\npub(crate) mod grpc;\n\n#[cfg(test)]\npub(crate) mod proto;\n"
  },
  {
    "path": "tonic-xds/src/testutil/proto/helloworld.rs",
    "content": "// This file is @generated by prost-build.\n/// The request message containing the user's name.\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct HelloRequest {\n    #[prost(string, tag = \"1\")]\n    pub name: ::prost::alloc::string::String,\n}\n/// The response message containing the greetings\n#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]\npub struct HelloReply {\n    #[prost(string, tag = \"1\")]\n    pub message: ::prost::alloc::string::String,\n}\n/// Generated client implementations.\npub mod greeter_client {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value\n    )]\n    use tonic::codegen::http::Uri;\n    use tonic::codegen::*;\n    /// The greeting service definition.\n    #[derive(Debug, Clone)]\n    pub struct GreeterClient<T> {\n        inner: tonic::client::Grpc<T>,\n    }\n    impl GreeterClient<tonic::transport::Channel> {\n        /// Attempt to create a new client by connecting to a given endpoint.\n        pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>\n        where\n            D: TryInto<tonic::transport::Endpoint>,\n            D::Error: Into<StdError>,\n        {\n            let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;\n            Ok(Self::new(conn))\n        }\n    }\n    impl<T> GreeterClient<T>\n    where\n        T: tonic::client::GrpcService<tonic::body::Body>,\n        T::Error: Into<StdError>,\n        T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,\n        <T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,\n    {\n        pub fn new(inner: T) -> Self {\n            let inner = tonic::client::Grpc::new(inner);\n            Self { inner }\n        }\n        pub fn with_origin(inner: T, origin: Uri) -> Self {\n            let inner = tonic::client::Grpc::with_origin(inner, origin);\n            Self { inner }\n        }\n        pub fn with_interceptor<F>(\n            inner: T,\n            interceptor: F,\n        ) -> GreeterClient<InterceptedService<T, F>>\n        where\n            F: tonic::service::Interceptor,\n            T::ResponseBody: Default,\n            T: tonic::codegen::Service<\n                    http::Request<tonic::body::Body>,\n                    Response = http::Response<\n                        <T as tonic::client::GrpcService<tonic::body::Body>>::ResponseBody,\n                    >,\n                >,\n            <T as tonic::codegen::Service<http::Request<tonic::body::Body>>>::Error:\n                Into<StdError> + std::marker::Send + std::marker::Sync,\n        {\n            GreeterClient::new(InterceptedService::new(inner, interceptor))\n        }\n        /// Compress requests with the given encoding.\n        ///\n        /// This requires the server to support it otherwise it might respond with an\n        /// error.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.send_compressed(encoding);\n            self\n        }\n        /// Enable decompressing responses.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.inner = self.inner.accept_compressed(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_decoding_message_size(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.inner = self.inner.max_encoding_message_size(limit);\n            self\n        }\n        /// Sends a greeting\n        pub async fn say_hello(\n            &mut self,\n            request: impl tonic::IntoRequest<super::HelloRequest>,\n        ) -> std::result::Result<tonic::Response<super::HelloReply>, tonic::Status> {\n            self.inner.ready().await.map_err(|e| {\n                tonic::Status::unknown(format!(\"Service was not ready: {}\", e.into()))\n            })?;\n            let codec = tonic_prost::ProstCodec::default();\n            let path = http::uri::PathAndQuery::from_static(\"/helloworld.Greeter/SayHello\");\n            let mut req = request.into_request();\n            req.extensions_mut()\n                .insert(GrpcMethod::new(\"helloworld.Greeter\", \"SayHello\"));\n            self.inner.unary(req, path, codec).await\n        }\n    }\n}\n/// Generated server implementations.\npub mod greeter_server {\n    #![allow(\n        unused_variables,\n        dead_code,\n        missing_docs,\n        clippy::wildcard_imports,\n        clippy::let_unit_value\n    )]\n    use tonic::codegen::*;\n    /// Generated trait containing gRPC methods that should be implemented for use with GreeterServer.\n    #[async_trait]\n    pub trait Greeter: std::marker::Send + std::marker::Sync + 'static {\n        /// Sends a greeting\n        async fn say_hello(\n            &self,\n            request: tonic::Request<super::HelloRequest>,\n        ) -> std::result::Result<tonic::Response<super::HelloReply>, tonic::Status>;\n    }\n    /// The greeting service definition.\n    #[derive(Debug)]\n    pub struct GreeterServer<T> {\n        inner: Arc<T>,\n        accept_compression_encodings: EnabledCompressionEncodings,\n        send_compression_encodings: EnabledCompressionEncodings,\n        max_decoding_message_size: Option<usize>,\n        max_encoding_message_size: Option<usize>,\n    }\n    impl<T> GreeterServer<T> {\n        pub fn new(inner: T) -> Self {\n            Self::from_arc(Arc::new(inner))\n        }\n        pub fn from_arc(inner: Arc<T>) -> Self {\n            Self {\n                inner,\n                accept_compression_encodings: Default::default(),\n                send_compression_encodings: Default::default(),\n                max_decoding_message_size: None,\n                max_encoding_message_size: None,\n            }\n        }\n        pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>\n        where\n            F: tonic::service::Interceptor,\n        {\n            InterceptedService::new(Self::new(inner), interceptor)\n        }\n        /// Enable decompressing requests with the given encoding.\n        #[must_use]\n        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.accept_compression_encodings.enable(encoding);\n            self\n        }\n        /// Compress responses with the given encoding, if the client supports it.\n        #[must_use]\n        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {\n            self.send_compression_encodings.enable(encoding);\n            self\n        }\n        /// Limits the maximum size of a decoded message.\n        ///\n        /// Default: `4MB`\n        #[must_use]\n        pub fn max_decoding_message_size(mut self, limit: usize) -> Self {\n            self.max_decoding_message_size = Some(limit);\n            self\n        }\n        /// Limits the maximum size of an encoded message.\n        ///\n        /// Default: `usize::MAX`\n        #[must_use]\n        pub fn max_encoding_message_size(mut self, limit: usize) -> Self {\n            self.max_encoding_message_size = Some(limit);\n            self\n        }\n    }\n    impl<T, B> tonic::codegen::Service<http::Request<B>> for GreeterServer<T>\n    where\n        T: Greeter,\n        B: Body + std::marker::Send + 'static,\n        B::Error: Into<StdError> + std::marker::Send + 'static,\n    {\n        type Response = http::Response<tonic::body::Body>;\n        type Error = std::convert::Infallible;\n        type Future = BoxFuture<Self::Response, Self::Error>;\n        fn poll_ready(\n            &mut self,\n            _cx: &mut Context<'_>,\n        ) -> Poll<std::result::Result<(), Self::Error>> {\n            Poll::Ready(Ok(()))\n        }\n        fn call(&mut self, req: http::Request<B>) -> Self::Future {\n            match req.uri().path() {\n                \"/helloworld.Greeter/SayHello\" => {\n                    #[allow(non_camel_case_types)]\n                    struct SayHelloSvc<T: Greeter>(pub Arc<T>);\n                    impl<T: Greeter> tonic::server::UnaryService<super::HelloRequest> for SayHelloSvc<T> {\n                        type Response = super::HelloReply;\n                        type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;\n                        fn call(\n                            &mut self,\n                            request: tonic::Request<super::HelloRequest>,\n                        ) -> Self::Future {\n                            let inner = Arc::clone(&self.0);\n                            let fut =\n                                async move { <T as Greeter>::say_hello(&inner, request).await };\n                            Box::pin(fut)\n                        }\n                    }\n                    let accept_compression_encodings = self.accept_compression_encodings;\n                    let send_compression_encodings = self.send_compression_encodings;\n                    let max_decoding_message_size = self.max_decoding_message_size;\n                    let max_encoding_message_size = self.max_encoding_message_size;\n                    let inner = self.inner.clone();\n                    let fut = async move {\n                        let method = SayHelloSvc(inner);\n                        let codec = tonic_prost::ProstCodec::default();\n                        let mut grpc = tonic::server::Grpc::new(codec)\n                            .apply_compression_config(\n                                accept_compression_encodings,\n                                send_compression_encodings,\n                            )\n                            .apply_max_message_size_config(\n                                max_decoding_message_size,\n                                max_encoding_message_size,\n                            );\n                        let res = grpc.unary(method, req).await;\n                        Ok(res)\n                    };\n                    Box::pin(fut)\n                }\n                _ => Box::pin(async move {\n                    let mut response = http::Response::new(tonic::body::Body::default());\n                    let headers = response.headers_mut();\n                    headers.insert(\n                        tonic::Status::GRPC_STATUS,\n                        (tonic::Code::Unimplemented as i32).into(),\n                    );\n                    headers.insert(\n                        http::header::CONTENT_TYPE,\n                        tonic::metadata::GRPC_CONTENT_TYPE,\n                    );\n                    Ok(response)\n                }),\n            }\n        }\n    }\n    impl<T> Clone for GreeterServer<T> {\n        fn clone(&self) -> Self {\n            let inner = self.inner.clone();\n            Self {\n                inner,\n                accept_compression_encodings: self.accept_compression_encodings,\n                send_compression_encodings: self.send_compression_encodings,\n                max_decoding_message_size: self.max_decoding_message_size,\n                max_encoding_message_size: self.max_encoding_message_size,\n            }\n        }\n    }\n    /// Generated gRPC service name\n    pub const SERVICE_NAME: &str = \"helloworld.Greeter\";\n    impl<T> tonic::server::NamedService for GreeterServer<T> {\n        const NAME: &'static str = SERVICE_NAME;\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/testutil/proto/mod.rs",
    "content": "//! This module contains Protobuf definitions for tests.\n//! To regenerate, run `cargo run -p tonic-xds --example gen_test_proto`.\n\n#[cfg(test)]\n#[allow(unreachable_pub, missing_docs)]\npub(crate) mod helloworld;\n"
  },
  {
    "path": "tonic-xds/src/xds/bootstrap.rs",
    "content": "#![allow(dead_code)]\n//! xDS bootstrap configuration.\n//!\n//! Parses the bootstrap JSON from `GRPC_XDS_BOOTSTRAP` (file path) or\n//! `GRPC_XDS_BOOTSTRAP_CONFIG` (inline JSON) environment variables,\n//! per gRFC A27.\n\nuse serde::Deserialize;\nuse xds_client::message::{Locality, Node};\n\n/// Environment variable pointing to a bootstrap JSON file path.\nconst ENV_BOOTSTRAP_FILE: &str = \"GRPC_XDS_BOOTSTRAP\";\n/// Environment variable containing inline bootstrap JSON.\nconst ENV_BOOTSTRAP_CONFIG: &str = \"GRPC_XDS_BOOTSTRAP_CONFIG\";\n\n/// Parsed xDS bootstrap configuration.\n#[derive(Debug, Clone, Deserialize)]\n#[non_exhaustive]\npub(crate) struct BootstrapConfig {\n    /// xDS management servers to connect to.\n    pub xds_servers: Vec<XdsServerConfig>,\n    /// Node identity sent to the xDS server.\n    #[serde(default)]\n    pub node: NodeConfig,\n}\n\n/// Configuration for a single xDS management server.\n#[derive(Debug, Clone, Deserialize)]\npub(crate) struct XdsServerConfig {\n    /// URI of the xDS server (e.g., `\"xds.example.com:443\"`).\n    pub server_uri: String,\n    /// Ordered list of channel credentials. The client uses the first supported type.\n    #[serde(default)]\n    pub channel_creds: Vec<ChannelCredentialConfig>,\n    /// Server features (e.g., `[\"xds_v3\"]`).\n    #[serde(default)]\n    pub server_features: Vec<String>,\n}\n\n/// A channel credential entry from the bootstrap config.\n#[derive(Debug, Clone, Deserialize)]\npub(crate) struct ChannelCredentialConfig {\n    /// Credential type (e.g., `\"insecure\"`, `\"tls\"`, `\"google_default\"`).\n    #[serde(rename = \"type\")]\n    pub cred_type: ChannelCredentialType,\n}\n\n/// Channel credential type from the bootstrap config.\n///\n/// Known types are deserialized into specific variants; unrecognized types\n/// are captured as `Unsupported(String)` so they can be skipped gracefully.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub(crate) enum ChannelCredentialType {\n    Insecure,\n    Tls,\n    #[serde(untagged)]\n    Unsupported(String),\n}\n\n/// Node identity configuration from bootstrap JSON.\n#[derive(Debug, Clone, Default, Deserialize)]\npub(crate) struct NodeConfig {\n    /// Opaque node identifier.\n    #[serde(default)]\n    pub id: String,\n    /// Cluster the node belongs to.\n    pub cluster: Option<String>,\n    /// Locality where the node is running.\n    pub locality: Option<LocalityConfig>,\n}\n\n/// Locality configuration from bootstrap JSON.\n#[derive(Debug, Clone, Deserialize)]\npub(crate) struct LocalityConfig {\n    #[serde(default)]\n    pub region: String,\n    #[serde(default)]\n    pub zone: String,\n    #[serde(default)]\n    pub sub_zone: String,\n}\n\n/// Errors that can occur when loading bootstrap configuration.\n#[derive(Debug, thiserror::Error)]\npub(crate) enum BootstrapError {\n    #[error(\"neither {ENV_BOOTSTRAP_FILE} nor {ENV_BOOTSTRAP_CONFIG} environment variable is set\")]\n    NotConfigured,\n    #[error(\"failed to read bootstrap file '{path}': {source}\")]\n    ReadFile {\n        path: String,\n        source: std::io::Error,\n    },\n    #[error(\"failed to parse bootstrap JSON: {0}\")]\n    InvalidJson(#[from] serde_json::Error),\n    #[error(\"bootstrap config validation failed: {0}\")]\n    Validation(String),\n}\n\nimpl BootstrapConfig {\n    /// Create a bootstrap configuration directly from struct fields.\n    pub(crate) fn new(\n        xds_servers: Vec<XdsServerConfig>,\n        node: NodeConfig,\n    ) -> Result<Self, BootstrapError> {\n        let config = Self { xds_servers, node };\n        config.validate()?;\n        Ok(config)\n    }\n\n    /// Load bootstrap configuration from environment variables.\n    ///\n    /// Checks `GRPC_XDS_BOOTSTRAP` (file path) first, then falls back to\n    /// `GRPC_XDS_BOOTSTRAP_CONFIG` (inline JSON).\n    pub(crate) fn from_env() -> Result<Self, BootstrapError> {\n        if let Ok(path) = std::env::var(ENV_BOOTSTRAP_FILE) {\n            let json = std::fs::read_to_string(&path)\n                .map_err(|e| BootstrapError::ReadFile { path, source: e })?;\n            return Self::from_json(&json);\n        }\n\n        if let Ok(json) = std::env::var(ENV_BOOTSTRAP_CONFIG) {\n            return Self::from_json(&json);\n        }\n\n        Err(BootstrapError::NotConfigured)\n    }\n\n    /// Parse bootstrap configuration from a JSON string.\n    pub(crate) fn from_json(json: &str) -> Result<Self, BootstrapError> {\n        let config: BootstrapConfig = serde_json::from_str(json)?;\n        config.validate()?;\n        Ok(config)\n    }\n\n    fn validate(&self) -> Result<(), BootstrapError> {\n        if self.xds_servers.is_empty() {\n            return Err(BootstrapError::Validation(\n                \"xds_servers must not be empty\".into(),\n            ));\n        }\n        for (i, server) in self.xds_servers.iter().enumerate() {\n            if server.server_uri.is_empty() {\n                return Err(BootstrapError::Validation(format!(\n                    \"xds_servers[{i}].server_uri must not be empty\"\n                )));\n            }\n        }\n        Ok(())\n    }\n\n    /// Returns the URI of the first xDS server.\n    pub(crate) fn server_uri(&self) -> &str {\n        self.xds_servers\n            .first()\n            .map(|s| s.server_uri.as_str())\n            .expect(\"xds_servers validated non-empty\")\n    }\n\n    /// Select the first supported channel credential type from the first server's config.\n    ///\n    /// Per gRFC A27, the client stops at the first credential type it supports.\n    /// Returns `None` if no supported credential type is found.\n    pub(crate) fn selected_credential(&self) -> Option<&ChannelCredentialType> {\n        self.xds_servers\n            .first()?\n            .channel_creds\n            .iter()\n            .map(|c| &c.cred_type)\n            .find(|t| {\n                matches!(\n                    t,\n                    ChannelCredentialType::Insecure | ChannelCredentialType::Tls\n                )\n            })\n    }\n}\n\nimpl From<NodeConfig> for Node {\n    fn from(config: NodeConfig) -> Self {\n        let mut node = Node::new(\"tonic-xds\", env!(\"CARGO_PKG_VERSION\"));\n\n        if !config.id.is_empty() {\n            node = node.with_id(config.id);\n        }\n        if let Some(cluster) = config.cluster {\n            node = node.with_cluster(cluster);\n        }\n        if let Some(locality) = config.locality {\n            node = node.with_locality(Locality {\n                region: locality.region,\n                zone: locality.zone,\n                sub_zone: locality.sub_zone,\n            });\n        }\n\n        node\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn minimal_json() -> &'static str {\n        r#\"{\n            \"xds_servers\": [{\"server_uri\": \"xds.example.com:443\"}],\n            \"node\": {\"id\": \"test-node\"}\n        }\"#\n    }\n\n    fn full_json() -> &'static str {\n        r#\"{\n            \"xds_servers\": [{\n                \"server_uri\": \"xds.example.com:443\",\n                \"channel_creds\": [\n                    {\"type\": \"google_default\"},\n                    {\"type\": \"tls\"},\n                    {\"type\": \"insecure\"}\n                ],\n                \"server_features\": [\"xds_v3\"]\n            }],\n            \"node\": {\n                \"id\": \"projects/123/nodes/456\",\n                \"cluster\": \"test-cluster\",\n                \"locality\": {\n                    \"region\": \"us-east1\",\n                    \"zone\": \"us-east1-b\",\n                    \"sub_zone\": \"rack1\"\n                }\n            }\n        }\"#\n    }\n\n    #[test]\n    fn parse_minimal() {\n        let config = BootstrapConfig::from_json(minimal_json()).unwrap();\n        assert_eq!(config.xds_servers.len(), 1);\n        assert_eq!(config.server_uri(), \"xds.example.com:443\");\n        assert_eq!(config.node.id, \"test-node\");\n        assert!(config.node.cluster.is_none());\n        assert!(config.node.locality.is_none());\n    }\n\n    #[test]\n    fn parse_full() {\n        let config = BootstrapConfig::from_json(full_json()).unwrap();\n        assert_eq!(config.xds_servers[0].server_uri, \"xds.example.com:443\");\n        assert_eq!(config.xds_servers[0].channel_creds.len(), 3);\n        assert!(matches!(\n            config.xds_servers[0].channel_creds[0].cred_type,\n            ChannelCredentialType::Unsupported(_)\n        ));\n        assert_eq!(config.xds_servers[0].server_features, vec![\"xds_v3\"]);\n        assert_eq!(config.node.id, \"projects/123/nodes/456\");\n        assert_eq!(config.node.cluster.as_deref(), Some(\"test-cluster\"));\n\n        let locality = config.node.locality.as_ref().unwrap();\n        assert_eq!(locality.region, \"us-east1\");\n        assert_eq!(locality.zone, \"us-east1-b\");\n        assert_eq!(locality.sub_zone, \"rack1\");\n    }\n\n    #[test]\n    fn node_from_full_config() {\n        let config = BootstrapConfig::from_json(full_json()).unwrap();\n        let node = Node::from(config.node);\n        assert_eq!(node.id.as_deref(), Some(\"projects/123/nodes/456\"));\n        assert_eq!(node.cluster.as_deref(), Some(\"test-cluster\"));\n        assert_eq!(node.user_agent_name, \"tonic-xds\");\n\n        let locality = node.locality.unwrap();\n        assert_eq!(locality.region, \"us-east1\");\n        assert_eq!(locality.zone, \"us-east1-b\");\n        assert_eq!(locality.sub_zone, \"rack1\");\n    }\n\n    #[test]\n    fn node_from_minimal_config() {\n        let config = BootstrapConfig::from_json(minimal_json()).unwrap();\n        let node = Node::from(config.node);\n        assert_eq!(node.id.as_deref(), Some(\"test-node\"));\n        assert!(node.cluster.is_none());\n        assert!(node.locality.is_none());\n    }\n\n    #[test]\n    fn selected_credential_first_supported_wins() {\n        let config = BootstrapConfig::from_json(full_json()).unwrap();\n        // google_default skipped, tls is first supported\n        assert_eq!(\n            config.selected_credential(),\n            Some(&ChannelCredentialType::Tls)\n        );\n    }\n\n    #[test]\n    fn selected_credential_insecure() {\n        let json = r#\"{\n            \"xds_servers\": [{\n                \"server_uri\": \"localhost:5000\",\n                \"channel_creds\": [{\"type\": \"insecure\"}]\n            }],\n            \"node\": {\"id\": \"n1\"}\n        }\"#;\n        let config = BootstrapConfig::from_json(json).unwrap();\n        assert_eq!(\n            config.selected_credential(),\n            Some(&ChannelCredentialType::Insecure)\n        );\n    }\n\n    #[test]\n    fn selected_credential_none_supported() {\n        let json = r#\"{\n            \"xds_servers\": [{\n                \"server_uri\": \"localhost:5000\",\n                \"channel_creds\": [{\"type\": \"google_default\"}]\n            }],\n            \"node\": {\"id\": \"n1\"}\n        }\"#;\n        let config = BootstrapConfig::from_json(json).unwrap();\n        assert_eq!(config.selected_credential(), None);\n    }\n\n    #[test]\n    fn selected_credential_empty_creds() {\n        let config = BootstrapConfig::from_json(minimal_json()).unwrap();\n        assert_eq!(config.selected_credential(), None);\n    }\n\n    #[test]\n    fn empty_xds_servers_fails() {\n        let json = r#\"{\"xds_servers\": [], \"node\": {\"id\": \"n1\"}}\"#;\n        let err = BootstrapConfig::from_json(json).unwrap_err();\n        assert!(err.to_string().contains(\"xds_servers must not be empty\"));\n    }\n\n    #[test]\n    fn empty_server_uri_fails() {\n        let json = r#\"{\"xds_servers\": [{\"server_uri\": \"\"}], \"node\": {\"id\": \"n1\"}}\"#;\n        let err = BootstrapConfig::from_json(json).unwrap_err();\n        assert!(err.to_string().contains(\"server_uri must not be empty\"));\n    }\n\n    #[test]\n    fn invalid_json_fails() {\n        let err = BootstrapConfig::from_json(\"not json\").unwrap_err();\n        assert!(matches!(err, BootstrapError::InvalidJson(_)));\n    }\n\n    #[test]\n    fn missing_required_field_fails() {\n        let json = r#\"{\"node\": {\"id\": \"n1\"}}\"#;\n        let err = BootstrapConfig::from_json(json).unwrap_err();\n        assert!(err.to_string().contains(\"xds_servers\"));\n    }\n\n    #[test]\n    fn node_without_id() {\n        let json = r#\"{\n            \"xds_servers\": [{\"server_uri\": \"localhost:5000\"}]\n        }\"#;\n        let config = BootstrapConfig::from_json(json).unwrap();\n        let node = Node::from(config.node);\n        assert!(node.id.is_none());\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/xds/mod.rs",
    "content": "pub(crate) mod bootstrap;\npub(crate) mod resource;\n// TODO: remove dead_code once routing is wired into the client layer\n#[allow(dead_code)]\npub(crate) mod routing;\npub(crate) mod uri;\npub(crate) mod xds_manager;\n"
  },
  {
    "path": "tonic-xds/src/xds/resource/cluster.rs",
    "content": "//! Validated Cluster resource (CDS).\n\nuse bytes::Bytes;\nuse envoy_types::pb::envoy::config::cluster::v3::{Cluster, cluster};\nuse prost::Message;\nuse xds_client::resource::TypeUrl;\nuse xds_client::{Error, Resource};\n\n/// Validated Cluster resource.\n#[derive(Debug, Clone)]\npub(crate) struct ClusterResource {\n    pub name: String,\n    /// The EDS service name for endpoint discovery.\n    /// If not set, the cluster name is used.\n    pub eds_service_name: Option<String>,\n    /// The load balancing policy for this cluster.\n    pub lb_policy: LbPolicy,\n}\n\n/// Load balancing policies.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub(crate) enum LbPolicy {\n    RoundRobin,\n    LeastRequest,\n}\n\nimpl Resource for ClusterResource {\n    type Message = Cluster;\n\n    const TYPE_URL: TypeUrl = TypeUrl::new(\"type.googleapis.com/envoy.config.cluster.v3.Cluster\");\n\n    const ALL_RESOURCES_REQUIRED_IN_SOTW: bool = true;\n\n    fn deserialize(bytes: Bytes) -> xds_client::Result<Self::Message> {\n        Cluster::decode(bytes).map_err(Into::into)\n    }\n\n    fn name(message: &Self::Message) -> &str {\n        &message.name\n    }\n\n    fn validate(message: Self::Message) -> xds_client::Result<Self> {\n        let name = message.name;\n        if name.is_empty() {\n            return Err(Error::Validation(\"cluster name is empty\".into()));\n        }\n\n        let eds_service_name = message\n            .eds_cluster_config\n            .map(|eds| eds.service_name)\n            .filter(|s| !s.is_empty());\n\n        let lb_policy = match cluster::LbPolicy::try_from(message.lb_policy) {\n            Ok(cluster::LbPolicy::RoundRobin) => LbPolicy::RoundRobin,\n            Ok(cluster::LbPolicy::LeastRequest) => LbPolicy::LeastRequest,\n            _ => {\n                return Err(Error::Validation(format!(\n                    \"unsupported load balancing policy: {}\",\n                    message.lb_policy\n                )));\n            }\n        };\n\n        Ok(ClusterResource {\n            name,\n            eds_service_name,\n            lb_policy,\n        })\n    }\n}\n\nimpl ClusterResource {\n    /// Returns the EDS service name for cascading EDS subscriptions.\n    /// Falls back to the cluster name if no EDS service name is set.\n    pub(crate) fn eds_service_name(&self) -> &str {\n        self.eds_service_name.as_deref().unwrap_or(&self.name)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use envoy_types::pb::envoy::config::cluster::v3::cluster::EdsClusterConfig;\n\n    fn make_cluster(name: &str) -> Cluster {\n        Cluster {\n            name: name.to_string(),\n            lb_policy: cluster::LbPolicy::RoundRobin as i32,\n            ..Default::default()\n        }\n    }\n\n    #[test]\n    fn test_validate_basic() {\n        let cluster = make_cluster(\"my-cluster\");\n        let validated = ClusterResource::validate(cluster).expect(\"should validate\");\n        assert_eq!(validated.name, \"my-cluster\");\n        assert_eq!(validated.lb_policy, LbPolicy::RoundRobin);\n        assert!(validated.eds_service_name.is_none());\n    }\n\n    #[test]\n    fn test_eds_service_name_defaults_to_cluster_name() {\n        let cluster = make_cluster(\"my-cluster\");\n        let validated = ClusterResource::validate(cluster).unwrap();\n        assert_eq!(validated.eds_service_name(), \"my-cluster\");\n    }\n\n    #[test]\n    fn test_eds_service_name() {\n        let cluster = Cluster {\n            name: \"my-cluster\".to_string(),\n            eds_cluster_config: Some(EdsClusterConfig {\n                service_name: \"eds-svc\".to_string(),\n                ..Default::default()\n            }),\n            lb_policy: cluster::LbPolicy::RoundRobin as i32,\n            ..Default::default()\n        };\n        let validated = ClusterResource::validate(cluster).unwrap();\n        assert_eq!(validated.eds_service_name.as_deref(), Some(\"eds-svc\"));\n        assert_eq!(validated.eds_service_name(), \"eds-svc\");\n    }\n\n    #[test]\n    fn test_least_request_lb_policy() {\n        let cluster = Cluster {\n            name: \"lr-cluster\".to_string(),\n            lb_policy: cluster::LbPolicy::LeastRequest as i32,\n            ..Default::default()\n        };\n        let validated = ClusterResource::validate(cluster).unwrap();\n        assert_eq!(validated.lb_policy, LbPolicy::LeastRequest);\n    }\n\n    #[test]\n    fn test_unsupported_lb_policy_is_rejected() {\n        let cluster = Cluster {\n            name: \"rh-cluster\".to_string(),\n            lb_policy: cluster::LbPolicy::RingHash as i32,\n            ..Default::default()\n        };\n        let err = ClusterResource::validate(cluster).unwrap_err();\n        assert!(\n            err.to_string()\n                .contains(\"unsupported load balancing policy\")\n        );\n    }\n\n    #[test]\n    fn test_validate_empty_name() {\n        let cluster = make_cluster(\"\");\n        let err = ClusterResource::validate(cluster).unwrap_err();\n        assert!(err.to_string().contains(\"cluster name is empty\"));\n    }\n\n    #[test]\n    fn test_all_resources_required() {\n        assert!(ClusterResource::ALL_RESOURCES_REQUIRED_IN_SOTW);\n    }\n\n    #[test]\n    fn test_deserialize_roundtrip() {\n        let cluster = make_cluster(\"test\");\n        let bytes = cluster.encode_to_vec();\n        let deserialized = ClusterResource::deserialize(Bytes::from(bytes)).unwrap();\n        assert_eq!(ClusterResource::name(&deserialized), \"test\");\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/xds/resource/endpoints.rs",
    "content": "//! Validated ClusterLoadAssignment resource (EDS).\n\nuse bytes::Bytes;\nuse envoy_types::pb::envoy::config::core::v3::{\n    HealthStatus as EnvoyHealthStatus, address, socket_address,\n};\nuse envoy_types::pb::envoy::config::endpoint::v3::{\n    ClusterLoadAssignment, LbEndpoint, lb_endpoint,\n};\nuse prost::Message;\nuse xds_client::resource::TypeUrl;\nuse xds_client::{Error, Resource};\n\nuse crate::client::endpoint::EndpointAddress;\n\n/// Validated ClusterLoadAssignment (EDS resource).\n#[derive(Debug)]\npub(crate) struct EndpointsResource {\n    pub cluster_name: String,\n    pub localities: Vec<LocalityEndpoints>,\n}\n\n/// Endpoints within a locality.\n#[derive(Debug)]\npub(crate) struct LocalityEndpoints {\n    pub locality: Option<Locality>,\n    pub endpoints: Vec<ResolvedEndpoint>,\n    pub load_balancing_weight: u32,\n    pub priority: u32,\n}\n\n/// Locality information for a set of endpoints.\n#[derive(Debug, PartialEq, Eq, Hash)]\npub(crate) struct Locality {\n    pub region: String,\n    pub zone: String,\n    pub sub_zone: String,\n}\n\n/// A single validated endpoint.\n#[derive(Debug)]\npub(crate) struct ResolvedEndpoint {\n    pub address: EndpointAddress,\n    pub health_status: HealthStatus,\n    pub load_balancing_weight: u32,\n}\n\n/// Health status of an endpoint.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub(crate) enum HealthStatus {\n    Unknown,\n    Healthy,\n    Unhealthy,\n    Draining,\n}\n\nimpl From<i32> for HealthStatus {\n    fn from(value: i32) -> Self {\n        match EnvoyHealthStatus::try_from(value) {\n            Ok(EnvoyHealthStatus::Healthy) => Self::Healthy,\n            // Envoy's health_check.proto defines TIMEOUT as \"interpreted by Envoy as\n            // UNHEALTHY\". Per gRFC A27, only HEALTHY and UNKNOWN are considered usable.\n            Ok(EnvoyHealthStatus::Unhealthy) | Ok(EnvoyHealthStatus::Timeout) => Self::Unhealthy,\n            Ok(EnvoyHealthStatus::Draining) => Self::Draining,\n            _ => Self::Unknown,\n        }\n    }\n}\n\nimpl Resource for EndpointsResource {\n    type Message = ClusterLoadAssignment;\n\n    const TYPE_URL: TypeUrl =\n        TypeUrl::new(\"type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment\");\n\n    const ALL_RESOURCES_REQUIRED_IN_SOTW: bool = false;\n\n    fn deserialize(bytes: Bytes) -> xds_client::Result<Self::Message> {\n        ClusterLoadAssignment::decode(bytes).map_err(Into::into)\n    }\n\n    fn name(message: &Self::Message) -> &str {\n        &message.cluster_name\n    }\n\n    fn validate(message: Self::Message) -> xds_client::Result<Self> {\n        let cluster_name = message.cluster_name;\n        if cluster_name.is_empty() {\n            return Err(Error::Validation(\n                \"ClusterLoadAssignment missing cluster_name\".into(),\n            ));\n        }\n\n        let mut localities = Vec::with_capacity(message.endpoints.len());\n        for locality_endpoints in message.endpoints {\n            let mut endpoints = Vec::with_capacity(locality_endpoints.lb_endpoints.len());\n            for lb_ep in locality_endpoints.lb_endpoints {\n                if let Some(ep) = validate_lb_endpoint(lb_ep)? {\n                    endpoints.push(ep);\n                }\n            }\n\n            let weight = locality_endpoints\n                .load_balancing_weight\n                .map(|w| w.value)\n                .unwrap_or(0);\n\n            let locality = locality_endpoints.locality.map(|l| Locality {\n                region: l.region,\n                zone: l.zone,\n                sub_zone: l.sub_zone,\n            });\n\n            localities.push(LocalityEndpoints {\n                locality,\n                endpoints,\n                load_balancing_weight: weight,\n                priority: locality_endpoints.priority,\n            });\n        }\n\n        Ok(EndpointsResource {\n            cluster_name,\n            localities,\n        })\n    }\n}\n\nfn validate_lb_endpoint(lb_ep: LbEndpoint) -> xds_client::Result<Option<ResolvedEndpoint>> {\n    let health_status = HealthStatus::from(lb_ep.health_status);\n\n    let host_identifier = match lb_ep.host_identifier {\n        Some(lb_endpoint::HostIdentifier::Endpoint(ep)) => ep,\n        // Skip unsupported or missing host_identifier variants (e.g. named\n        // endpoints). These are not relevant to gRPC and should not cause the\n        // entire EDS resource to be NACKed — the control plane may be serving\n        // both envoy proxies and gRPC clients.\n        _ => return Ok(None),\n    };\n\n    let addr = host_identifier\n        .address\n        .ok_or_else(|| Error::Validation(\"endpoint missing address\".into()))?;\n\n    let addr = match addr.address {\n        Some(address::Address::SocketAddress(sa)) => {\n            let port = match sa.port_specifier {\n                Some(socket_address::PortSpecifier::PortValue(p)) => p as u16,\n                _ => {\n                    return Err(Error::Validation(\n                        \"endpoint address missing numeric port\".into(),\n                    ));\n                }\n            };\n            EndpointAddress::new(sa.address, port)\n        }\n        _ => {\n            return Err(Error::Validation(\n                \"only socket addresses are supported for gRPC endpoints\".into(),\n            ));\n        }\n    };\n\n    let weight = lb_ep.load_balancing_weight.map(|w| w.value).unwrap_or(1);\n\n    Ok(Some(ResolvedEndpoint {\n        address: addr,\n        health_status,\n        load_balancing_weight: weight,\n    }))\n}\n\nimpl EndpointsResource {\n    /// Returns all healthy endpoints (Unknown and Healthy status).\n    pub(crate) fn healthy_endpoints(&self) -> impl Iterator<Item = &ResolvedEndpoint> {\n        self.localities\n            .iter()\n            .flat_map(|l| &l.endpoints)\n            .filter(|e| {\n                matches!(\n                    e.health_status,\n                    HealthStatus::Unknown | HealthStatus::Healthy\n                )\n            })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use envoy_types::pb::envoy::config::core::v3::{Address, SocketAddress};\n    use envoy_types::pb::envoy::config::endpoint::v3::{Endpoint, LocalityLbEndpoints};\n    use envoy_types::pb::google::protobuf::UInt32Value;\n\n    fn make_lb_endpoint(ip: &str, port: u32, health: i32) -> LbEndpoint {\n        LbEndpoint {\n            host_identifier: Some(lb_endpoint::HostIdentifier::Endpoint(Endpoint {\n                address: Some(Address {\n                    address: Some(address::Address::SocketAddress(SocketAddress {\n                        address: ip.to_string(),\n                        port_specifier: Some(socket_address::PortSpecifier::PortValue(port)),\n                        ..Default::default()\n                    })),\n                }),\n                ..Default::default()\n            })),\n            health_status: health,\n            load_balancing_weight: Some(UInt32Value { value: 1 }),\n            ..Default::default()\n        }\n    }\n\n    fn make_cla(cluster_name: &str) -> ClusterLoadAssignment {\n        ClusterLoadAssignment {\n            cluster_name: cluster_name.to_string(),\n            endpoints: vec![LocalityLbEndpoints {\n                lb_endpoints: vec![\n                    make_lb_endpoint(\"10.0.0.1\", 8080, EnvoyHealthStatus::Healthy as i32),\n                    make_lb_endpoint(\"10.0.0.2\", 8080, EnvoyHealthStatus::Unknown as i32),\n                    make_lb_endpoint(\"10.0.0.3\", 8080, EnvoyHealthStatus::Unhealthy as i32),\n                ],\n                load_balancing_weight: Some(UInt32Value { value: 100 }),\n                priority: 0,\n                ..Default::default()\n            }],\n            ..Default::default()\n        }\n    }\n\n    #[test]\n    fn test_validate_basic() {\n        let cla = make_cla(\"my-cluster\");\n        let validated = EndpointsResource::validate(cla).expect(\"should validate\");\n        assert_eq!(validated.cluster_name, \"my-cluster\");\n        assert_eq!(validated.localities.len(), 1);\n        assert_eq!(validated.localities[0].endpoints.len(), 3);\n    }\n\n    #[test]\n    fn test_healthy_endpoints() {\n        let cla = make_cla(\"my-cluster\");\n        let validated = EndpointsResource::validate(cla).unwrap();\n        let healthy: Vec<_> = validated.healthy_endpoints().collect();\n        // Healthy + Unknown = 2 (Unhealthy excluded)\n        assert_eq!(healthy.len(), 2);\n    }\n\n    #[test]\n    fn test_validate_empty_cluster_name() {\n        let cla = ClusterLoadAssignment {\n            cluster_name: String::new(),\n            ..Default::default()\n        };\n        let err = EndpointsResource::validate(cla).unwrap_err();\n        assert!(err.to_string().contains(\"cluster_name\"));\n    }\n\n    #[test]\n    fn test_eds_allows_partial_responses_in_sotw() {\n        // EDS resources are per-cluster, so SotW responses may contain only a subset.\n        // Unlike LDS/CDS which require all resources in every SotW response.\n        assert!(!EndpointsResource::ALL_RESOURCES_REQUIRED_IN_SOTW);\n    }\n\n    #[test]\n    fn test_deserialize_roundtrip() {\n        let cla = make_cla(\"test\");\n        let bytes = cla.encode_to_vec();\n        let deserialized = EndpointsResource::deserialize(Bytes::from(bytes)).unwrap();\n        assert_eq!(EndpointsResource::name(&deserialized), \"test\");\n    }\n\n    #[test]\n    fn test_endpoint_with_weight() {\n        let cla = make_cla(\"c1\");\n        let validated = EndpointsResource::validate(cla).unwrap();\n        for ep in &validated.localities[0].endpoints {\n            assert_eq!(ep.load_balancing_weight, 1);\n        }\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/xds/resource/listener.rs",
    "content": "//! Validated Listener resource (LDS).\n\nuse bytes::Bytes;\nuse envoy_types::pb::envoy::config::listener::v3::Listener;\nuse envoy_types::pb::envoy::extensions::filters::network::http_connection_manager::v3::{\n    HttpConnectionManager, http_connection_manager::RouteSpecifier,\n};\nuse prost::Message;\nuse xds_client::resource::TypeUrl;\nuse xds_client::{Error, Resource};\n\nuse super::route_config::RouteConfigResource;\n\n/// How the listener obtains its route configuration.\n#[derive(Debug)]\npub(crate) enum RouteSource {\n    /// Route configuration fetched dynamically via RDS.\n    Rds(String),\n    /// Route configuration embedded inline in the listener.\n    Inline(RouteConfigResource),\n}\n\n/// Validated Listener resource.\n///\n/// Extracts the route source from the\n/// `ApiListener` -> `HttpConnectionManager` -> `route_specifier` chain.\n#[derive(Debug)]\npub(crate) struct ListenerResource {\n    pub name: String,\n    pub route_source: RouteSource,\n}\n\nimpl Resource for ListenerResource {\n    type Message = Listener;\n\n    const TYPE_URL: TypeUrl = TypeUrl::new(\"type.googleapis.com/envoy.config.listener.v3.Listener\");\n\n    const ALL_RESOURCES_REQUIRED_IN_SOTW: bool = true;\n\n    fn deserialize(bytes: Bytes) -> xds_client::Result<Self::Message> {\n        Listener::decode(bytes).map_err(Into::into)\n    }\n\n    fn name(message: &Self::Message) -> &str {\n        &message.name\n    }\n\n    fn validate(message: Self::Message) -> xds_client::Result<Self> {\n        let name = message.name;\n\n        // gRPC listeners must have an ApiListener.\n        let api_listener = message\n            .api_listener\n            .ok_or_else(|| Error::Validation(\"listener missing api_listener field\".into()))?;\n\n        // The ApiListener contains an Any that should be HttpConnectionManager.\n        let any = api_listener.api_listener.ok_or_else(|| {\n            Error::Validation(\"api_listener missing inner api_listener Any field\".into())\n        })?;\n\n        let hcm = HttpConnectionManager::decode(Bytes::from(any.value)).map_err(|e| {\n            Error::Validation(format!(\"failed to decode HttpConnectionManager: {e}\"))\n        })?;\n\n        let route_specifier = hcm.route_specifier.ok_or_else(|| {\n            Error::Validation(\"HttpConnectionManager missing route_specifier\".into())\n        })?;\n\n        match route_specifier {\n            RouteSpecifier::Rds(rds) => {\n                if rds.route_config_name.is_empty() {\n                    return Err(Error::Validation(\"RDS route_config_name is empty\".into()));\n                }\n                Ok(ListenerResource {\n                    name,\n                    route_source: RouteSource::Rds(rds.route_config_name),\n                })\n            }\n            RouteSpecifier::RouteConfig(route_config) => {\n                let validated = RouteConfigResource::validate(route_config)?;\n                Ok(ListenerResource {\n                    name,\n                    route_source: RouteSource::Inline(validated),\n                })\n            }\n            RouteSpecifier::ScopedRoutes(_) => Err(Error::Validation(\n                \"scoped_routes not supported for gRPC\".into(),\n            )),\n        }\n    }\n}\n\nimpl ListenerResource {\n    /// Returns the RDS route config name for cascading subscriptions.\n    pub(crate) fn route_config_name(&self) -> Option<&str> {\n        match &self.route_source {\n            RouteSource::Rds(name) => Some(name),\n            RouteSource::Inline(_) => None,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use envoy_types::pb::envoy::config::listener::v3::ApiListener;\n    use envoy_types::pb::envoy::extensions::filters::network::http_connection_manager::v3::Rds;\n    use envoy_types::pb::google::protobuf::Any;\n\n    fn make_rds_listener(name: &str, route_config_name: &str) -> Listener {\n        let rds = Rds {\n            route_config_name: route_config_name.to_string(),\n            ..Default::default()\n        };\n        let hcm = HttpConnectionManager {\n            route_specifier: Some(RouteSpecifier::Rds(rds)),\n            ..Default::default()\n        };\n        let hcm_any = Any {\n            type_url: \"type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\".to_string(),\n            value: hcm.encode_to_vec().into(),\n        };\n        Listener {\n            name: name.to_string(),\n            api_listener: Some(ApiListener {\n                api_listener: Some(hcm_any),\n            }),\n            ..Default::default()\n        }\n    }\n\n    #[test]\n    fn test_validate_rds_listener() {\n        let listener = make_rds_listener(\"test-listener\", \"route-config-1\");\n        let validated = ListenerResource::validate(listener).expect(\"should validate\");\n        assert_eq!(validated.name, \"test-listener\");\n        assert!(\n            matches!(&validated.route_source, RouteSource::Rds(name) if name == \"route-config-1\")\n        );\n        assert_eq!(validated.route_config_name(), Some(\"route-config-1\"));\n    }\n\n    #[test]\n    fn test_validate_missing_api_listener() {\n        let listener = Listener {\n            name: \"test-listener\".to_string(),\n            ..Default::default()\n        };\n        let err = ListenerResource::validate(listener).unwrap_err();\n        assert!(err.to_string().contains(\"api_listener\"));\n    }\n\n    #[test]\n    fn test_validate_empty_rds_name() {\n        let listener = make_rds_listener(\"test-listener\", \"\");\n        let err = ListenerResource::validate(listener).unwrap_err();\n        assert!(err.to_string().contains(\"route_config_name is empty\"));\n    }\n\n    #[test]\n    fn test_deserialize_valid() {\n        let listener = make_rds_listener(\"test\", \"rc1\");\n        let bytes = listener.encode_to_vec();\n        let deserialized =\n            ListenerResource::deserialize(Bytes::from(bytes)).expect(\"should deserialize\");\n        assert_eq!(ListenerResource::name(&deserialized), \"test\");\n    }\n\n    #[test]\n    fn test_deserialize_invalid_bytes() {\n        let result = ListenerResource::deserialize(Bytes::from_static(b\"invalid\"));\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_type_url() {\n        assert_eq!(\n            ListenerResource::TYPE_URL.as_str(),\n            \"type.googleapis.com/envoy.config.listener.v3.Listener\"\n        );\n    }\n\n    #[test]\n    fn test_all_resources_required() {\n        assert!(ListenerResource::ALL_RESOURCES_REQUIRED_IN_SOTW);\n    }\n\n    #[test]\n    fn test_validate_inline_route_config() {\n        use envoy_types::pb::envoy::config::route::v3::route_match::PathSpecifier;\n        use envoy_types::pb::envoy::config::route::v3::{\n            RouteAction, RouteConfiguration, RouteMatch, VirtualHost, route::Action,\n        };\n\n        let route_config = RouteConfiguration {\n            name: \"inline-rc\".to_string(),\n            virtual_hosts: vec![VirtualHost {\n                name: \"vh1\".to_string(),\n                domains: vec![\"*\".to_string()],\n                routes: vec![envoy_types::pb::envoy::config::route::v3::Route {\n                    r#match: Some(RouteMatch {\n                        path_specifier: Some(PathSpecifier::Prefix(\"/\".to_string())),\n                        ..Default::default()\n                    }),\n                    action: Some(Action::Route(RouteAction {\n                        cluster_specifier: Some(\n                            envoy_types::pb::envoy::config::route::v3::route_action::ClusterSpecifier::Cluster(\n                                \"cluster-1\".to_string(),\n                            ),\n                        ),\n                        ..Default::default()\n                    })),\n                    ..Default::default()\n                }],\n                ..Default::default()\n            }],\n            ..Default::default()\n        };\n\n        let hcm = HttpConnectionManager {\n            route_specifier: Some(RouteSpecifier::RouteConfig(route_config)),\n            ..Default::default()\n        };\n        let hcm_any = Any {\n            type_url: \"type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager\".to_string(),\n            value: hcm.encode_to_vec().into(),\n        };\n        let listener = Listener {\n            name: \"inline-listener\".to_string(),\n            api_listener: Some(ApiListener {\n                api_listener: Some(hcm_any),\n            }),\n            ..Default::default()\n        };\n\n        let validated = ListenerResource::validate(listener).expect(\"should validate\");\n        assert_eq!(validated.name, \"inline-listener\");\n        assert!(matches!(&validated.route_source, RouteSource::Inline(_)));\n        assert!(validated.route_config_name().is_none());\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/xds/resource/mod.rs",
    "content": "#![allow(dead_code, unused_imports)]\n//! xDS resource type implementations.\n//!\n//! Each module implements [`xds_client::Resource`] for one of the four resource types:\n//! - [`ListenerResource`] (LDS)\n//! - [`RouteConfigResource`] (RDS)\n//! - [`ClusterResource`] (CDS)\n//! - [`EndpointsResource`] (EDS)\n//!\n//! These are *validated* types containing only the fields relevant to gRPC\n\npub(crate) mod cluster;\npub(crate) mod endpoints;\npub(crate) mod listener;\npub(crate) mod route_config;\n\npub(crate) use cluster::{ClusterResource, LbPolicy};\npub(crate) use endpoints::{EndpointsResource, LocalityEndpoints, ResolvedEndpoint};\npub(crate) use listener::ListenerResource;\npub(crate) use route_config::{RouteConfigResource, VirtualHostConfig};\n"
  },
  {
    "path": "tonic-xds/src/xds/resource/route_config.rs",
    "content": "//! Validated RouteConfiguration resource (RDS).\n\nuse std::collections::HashSet;\n\nuse bytes::Bytes;\nuse envoy_types::pb::envoy::config::route::v3::{\n    RouteConfiguration, RouteMatch, route, route_action, route_match,\n};\nuse prost::Message;\nuse regex::Regex;\nuse xds_client::resource::TypeUrl;\nuse xds_client::{Error, Resource};\n\n/// Validated RouteConfiguration.\n#[derive(Debug, Clone)]\npub(crate) struct RouteConfigResource {\n    pub name: String,\n    pub virtual_hosts: Vec<VirtualHostConfig>,\n}\n\n/// Validated virtual host with domain matching and routes.\n#[derive(Debug, Clone)]\npub(crate) struct VirtualHostConfig {\n    pub name: String,\n    pub domains: Vec<String>,\n    pub routes: Vec<RouteConfig>,\n}\n\n/// A validated route with match criteria and action.\n#[derive(Debug, Clone)]\npub(crate) struct RouteConfig {\n    pub match_criteria: RouteConfigMatch,\n    pub action: RouteConfigAction,\n}\n\n/// Validated route match criteria.\n#[derive(Debug, Clone)]\npub(crate) struct RouteConfigMatch {\n    pub path_specifier: PathSpecifierConfig,\n    pub headers: Vec<HeaderMatcherConfig>,\n    pub case_sensitive: bool,\n}\n\n/// Path matching specifier.\n#[derive(Debug, Clone)]\npub(crate) enum PathSpecifierConfig {\n    Prefix(String),\n    Path(String),\n    SafeRegex(Regex),\n}\n\n/// Header matching criteria.\n#[derive(Debug, Clone)]\npub(crate) struct HeaderMatcherConfig {\n    pub name: String,\n    pub match_specifier: HeaderMatchSpecifierConfig,\n    pub invert_match: bool,\n}\n\n/// Header match specifier variants.\n#[derive(Debug, Clone)]\npub(crate) enum HeaderMatchSpecifierConfig {\n    Exact(String),\n    SafeRegex(Regex),\n    Prefix(String),\n    Suffix(String),\n    Contains(String),\n    /// Match if header is present (any value).\n    Present,\n}\n\n/// Route action deciding where to send traffic.\n#[derive(Debug, Clone)]\npub(crate) enum RouteConfigAction {\n    Cluster(String),\n    WeightedClusters(Vec<WeightedCluster>),\n}\n\n/// A cluster with an associated weight for traffic splitting.\n#[derive(Debug, Clone)]\npub(crate) struct WeightedCluster {\n    pub name: String,\n    pub weight: u32,\n}\n\nimpl Resource for RouteConfigResource {\n    type Message = RouteConfiguration;\n\n    const TYPE_URL: TypeUrl =\n        TypeUrl::new(\"type.googleapis.com/envoy.config.route.v3.RouteConfiguration\");\n\n    const ALL_RESOURCES_REQUIRED_IN_SOTW: bool = false;\n\n    fn deserialize(bytes: Bytes) -> xds_client::Result<Self::Message> {\n        RouteConfiguration::decode(bytes).map_err(Into::into)\n    }\n\n    fn name(message: &Self::Message) -> &str {\n        &message.name\n    }\n\n    fn validate(message: Self::Message) -> xds_client::Result<Self> {\n        let name = message.name;\n\n        if message.virtual_hosts.is_empty() {\n            return Err(Error::Validation(format!(\n                \"route configuration '{name}' has no virtual hosts\"\n            )));\n        }\n\n        let mut virtual_hosts = Vec::with_capacity(message.virtual_hosts.len());\n\n        for vh in message.virtual_hosts {\n            if vh.domains.is_empty() {\n                return Err(Error::Validation(format!(\n                    \"virtual host '{}' has no domains\",\n                    vh.name\n                )));\n            }\n\n            let mut routes = Vec::with_capacity(vh.routes.len());\n            for route in vh.routes {\n                let validated_route = validate_route(route)?;\n                routes.push(validated_route);\n            }\n\n            virtual_hosts.push(VirtualHostConfig {\n                name: vh.name,\n                domains: vh.domains,\n                routes,\n            });\n        }\n\n        Ok(RouteConfigResource {\n            name,\n            virtual_hosts,\n        })\n    }\n}\n\nfn validate_route(\n    route: envoy_types::pb::envoy::config::route::v3::Route,\n) -> xds_client::Result<RouteConfig> {\n    let route_match = route\n        .r#match\n        .ok_or_else(|| Error::Validation(\"route missing match field\".into()))?;\n\n    let match_criteria = validate_route_match(route_match)?;\n\n    let action = route\n        .action\n        .ok_or_else(|| Error::Validation(\"route missing action field\".into()))?;\n\n    let validated_action = match action {\n        route::Action::Route(route_action) => validate_route_action(route_action)?,\n        route::Action::NonForwardingAction(_) => {\n            // Non-forwarding actions are used in xDS server-side, not client-side.\n            return Err(Error::Validation(\n                \"non_forwarding_action not supported for client-side routing\".into(),\n            ));\n        }\n        _ => {\n            return Err(Error::Validation(\n                \"only route action is supported for client routing\".into(),\n            ));\n        }\n    };\n\n    Ok(RouteConfig {\n        match_criteria,\n        action: validated_action,\n    })\n}\n\nfn validate_route_match(rm: RouteMatch) -> xds_client::Result<RouteConfigMatch> {\n    let path_specifier = match rm.path_specifier {\n        Some(route_match::PathSpecifier::Prefix(p)) => PathSpecifierConfig::Prefix(p),\n        Some(route_match::PathSpecifier::Path(p)) => PathSpecifierConfig::Path(p),\n        Some(route_match::PathSpecifier::SafeRegex(r)) => {\n            let re = Regex::new(&r.regex)\n                .map_err(|e| Error::Validation(format!(\"invalid path regex '{}': {e}\", r.regex)))?;\n            PathSpecifierConfig::SafeRegex(re)\n        }\n        None => {\n            // Default: empty prefix matches everything.\n            PathSpecifierConfig::Prefix(String::new())\n        }\n        _ => {\n            return Err(Error::Validation(\n                \"unsupported path specifier variant\".into(),\n            ));\n        }\n    };\n\n    let case_sensitive = rm.case_sensitive.map(|v| v.value).unwrap_or(true);\n\n    let mut headers = Vec::with_capacity(rm.headers.len());\n    for hm in rm.headers {\n        let validated_hm = validate_header_matcher(hm)?;\n        headers.push(validated_hm);\n    }\n\n    Ok(RouteConfigMatch {\n        path_specifier,\n        headers,\n        case_sensitive,\n    })\n}\n\nfn validate_header_matcher(\n    hm: envoy_types::pb::envoy::config::route::v3::HeaderMatcher,\n) -> xds_client::Result<HeaderMatcherConfig> {\n    use envoy_types::pb::envoy::config::route::v3::header_matcher::HeaderMatchSpecifier;\n    use envoy_types::pb::envoy::r#type::matcher::v3::string_matcher::MatchPattern;\n\n    let match_specifier = match hm.header_match_specifier {\n        Some(HeaderMatchSpecifier::ExactMatch(v)) => HeaderMatchSpecifierConfig::Exact(v),\n        Some(HeaderMatchSpecifier::SafeRegexMatch(r)) => {\n            let re = Regex::new(&r.regex).map_err(|e| {\n                Error::Validation(format!(\"invalid header regex '{}': {e}\", r.regex))\n            })?;\n            HeaderMatchSpecifierConfig::SafeRegex(re)\n        }\n        Some(HeaderMatchSpecifier::PresentMatch(_)) => HeaderMatchSpecifierConfig::Present,\n        Some(HeaderMatchSpecifier::StringMatch(sm)) => match sm.match_pattern {\n            Some(MatchPattern::Exact(v)) => HeaderMatchSpecifierConfig::Exact(v),\n            Some(MatchPattern::Prefix(v)) => HeaderMatchSpecifierConfig::Prefix(v),\n            Some(MatchPattern::Suffix(v)) => HeaderMatchSpecifierConfig::Suffix(v),\n            Some(MatchPattern::Contains(v)) => HeaderMatchSpecifierConfig::Contains(v),\n            Some(MatchPattern::SafeRegex(r)) => {\n                let re = Regex::new(&r.regex).map_err(|e| {\n                    Error::Validation(format!(\"invalid header regex '{}': {e}\", r.regex))\n                })?;\n                HeaderMatchSpecifierConfig::SafeRegex(re)\n            }\n            _ => {\n                return Err(Error::Validation(\n                    \"unsupported StringMatcher pattern\".into(),\n                ));\n            }\n        },\n        None => HeaderMatchSpecifierConfig::Present,\n        _ => {\n            return Err(Error::Validation(\n                \"unsupported header match specifier\".into(),\n            ));\n        }\n    };\n\n    Ok(HeaderMatcherConfig {\n        name: hm.name,\n        match_specifier,\n        invert_match: hm.invert_match,\n    })\n}\n\nfn validate_route_action(\n    ra: envoy_types::pb::envoy::config::route::v3::RouteAction,\n) -> xds_client::Result<RouteConfigAction> {\n    match ra.cluster_specifier {\n        Some(route_action::ClusterSpecifier::Cluster(name)) => {\n            if name.is_empty() {\n                return Err(Error::Validation(\"cluster name is empty\".into()));\n            }\n            Ok(RouteConfigAction::Cluster(name))\n        }\n        Some(route_action::ClusterSpecifier::WeightedClusters(wc)) => {\n            if wc.clusters.is_empty() {\n                return Err(Error::Validation(\"weighted_clusters is empty\".into()));\n            }\n            let clusters: Vec<WeightedCluster> = wc\n                .clusters\n                .into_iter()\n                .map(|c| WeightedCluster {\n                    name: c.name,\n                    weight: c.weight.map(|w| w.value).unwrap_or(0),\n                })\n                .collect();\n            Ok(RouteConfigAction::WeightedClusters(clusters))\n        }\n        Some(_) => Err(Error::Validation(\n            \"unsupported cluster specifier variant\".into(),\n        )),\n        None => Err(Error::Validation(\n            \"route action missing cluster specifier\".into(),\n        )),\n    }\n}\n\nimpl RouteConfigResource {\n    /// Returns cluster names referenced by this route configuration for cascading CDS subscriptions.\n    pub(crate) fn cluster_names(&self) -> HashSet<String> {\n        let mut clusters = HashSet::new();\n        for vh in &self.virtual_hosts {\n            for route in &vh.routes {\n                match &route.action {\n                    RouteConfigAction::Cluster(name) => {\n                        clusters.insert(name.clone());\n                    }\n                    RouteConfigAction::WeightedClusters(wcs) => {\n                        for wc in wcs {\n                            clusters.insert(wc.name.clone());\n                        }\n                    }\n                }\n            }\n        }\n        clusters\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use envoy_types::pb::envoy::config::route::v3::{\n        RouteAction, VirtualHost, route::Action, route_action::ClusterSpecifier,\n    };\n\n    fn make_route(prefix: &str, cluster: &str) -> envoy_types::pb::envoy::config::route::v3::Route {\n        envoy_types::pb::envoy::config::route::v3::Route {\n            r#match: Some(RouteMatch {\n                path_specifier: Some(route_match::PathSpecifier::Prefix(prefix.to_string())),\n                ..Default::default()\n            }),\n            action: Some(Action::Route(RouteAction {\n                cluster_specifier: Some(ClusterSpecifier::Cluster(cluster.to_string())),\n                ..Default::default()\n            })),\n            ..Default::default()\n        }\n    }\n\n    fn make_route_config(name: &str) -> RouteConfiguration {\n        RouteConfiguration {\n            name: name.to_string(),\n            virtual_hosts: vec![VirtualHost {\n                name: \"vh1\".to_string(),\n                domains: vec![\"*\".to_string()],\n                routes: vec![make_route(\"/\", \"cluster-1\")],\n                ..Default::default()\n            }],\n            ..Default::default()\n        }\n    }\n\n    #[test]\n    fn test_validate_basic() {\n        let rc = make_route_config(\"rc-1\");\n        let validated = RouteConfigResource::validate(rc).expect(\"should validate\");\n        assert_eq!(validated.name, \"rc-1\");\n        assert_eq!(validated.virtual_hosts.len(), 1);\n        assert_eq!(validated.virtual_hosts[0].routes.len(), 1);\n    }\n\n    #[test]\n    fn test_cluster_names() {\n        let rc = make_route_config(\"rc-1\");\n        let validated = RouteConfigResource::validate(rc).unwrap();\n        let clusters = validated.cluster_names();\n        assert_eq!(clusters.len(), 1);\n        assert!(clusters.contains(\"cluster-1\"));\n    }\n\n    #[test]\n    fn test_validate_empty_domains() {\n        let rc = RouteConfiguration {\n            name: \"rc\".to_string(),\n            virtual_hosts: vec![VirtualHost {\n                name: \"vh-no-domains\".to_string(),\n                domains: vec![],\n                routes: vec![],\n                ..Default::default()\n            }],\n            ..Default::default()\n        };\n        let err = RouteConfigResource::validate(rc).unwrap_err();\n        assert!(err.to_string().contains(\"no domains\"));\n    }\n\n    #[test]\n    fn test_validate_empty_cluster_name() {\n        let rc = RouteConfiguration {\n            name: \"rc\".to_string(),\n            virtual_hosts: vec![VirtualHost {\n                name: \"vh1\".to_string(),\n                domains: vec![\"*\".to_string()],\n                routes: vec![make_route(\"/\", \"\")],\n                ..Default::default()\n            }],\n            ..Default::default()\n        };\n        let err = RouteConfigResource::validate(rc).unwrap_err();\n        assert!(err.to_string().contains(\"cluster name is empty\"));\n    }\n\n    #[test]\n    fn test_validate_exact_path() {\n        let route = envoy_types::pb::envoy::config::route::v3::Route {\n            r#match: Some(RouteMatch {\n                path_specifier: Some(route_match::PathSpecifier::Path(\n                    \"/service/Method\".to_string(),\n                )),\n                ..Default::default()\n            }),\n            action: Some(Action::Route(RouteAction {\n                cluster_specifier: Some(ClusterSpecifier::Cluster(\"c1\".to_string())),\n                ..Default::default()\n            })),\n            ..Default::default()\n        };\n        let rc = RouteConfiguration {\n            name: \"rc\".to_string(),\n            virtual_hosts: vec![VirtualHost {\n                name: \"vh1\".to_string(),\n                domains: vec![\"*\".to_string()],\n                routes: vec![route],\n                ..Default::default()\n            }],\n            ..Default::default()\n        };\n        let validated = RouteConfigResource::validate(rc).unwrap();\n        assert!(matches!(\n            &validated.virtual_hosts[0].routes[0]\n                .match_criteria\n                .path_specifier,\n            PathSpecifierConfig::Path(p) if p == \"/service/Method\"\n        ));\n    }\n\n    #[test]\n    fn test_cascade_weighted_clusters() {\n        use envoy_types::pb::envoy::config::route::v3::{\n            WeightedCluster, weighted_cluster::ClusterWeight,\n        };\n        use envoy_types::pb::google::protobuf::UInt32Value;\n\n        let route = envoy_types::pb::envoy::config::route::v3::Route {\n            r#match: Some(RouteMatch {\n                path_specifier: Some(route_match::PathSpecifier::Prefix(\"/\".to_string())),\n                ..Default::default()\n            }),\n            action: Some(Action::Route(RouteAction {\n                cluster_specifier: Some(route_action::ClusterSpecifier::WeightedClusters(\n                    WeightedCluster {\n                        clusters: vec![\n                            ClusterWeight {\n                                name: \"c1\".to_string(),\n                                weight: Some(UInt32Value { value: 70 }),\n                                ..Default::default()\n                            },\n                            ClusterWeight {\n                                name: \"c2\".to_string(),\n                                weight: Some(UInt32Value { value: 30 }),\n                                ..Default::default()\n                            },\n                        ],\n                        ..Default::default()\n                    },\n                )),\n                ..Default::default()\n            })),\n            ..Default::default()\n        };\n        let rc = RouteConfiguration {\n            name: \"rc\".to_string(),\n            virtual_hosts: vec![VirtualHost {\n                name: \"vh1\".to_string(),\n                domains: vec![\"*\".to_string()],\n                routes: vec![route],\n                ..Default::default()\n            }],\n            ..Default::default()\n        };\n        let validated = RouteConfigResource::validate(rc).unwrap();\n        let clusters = validated.cluster_names();\n        assert_eq!(clusters.len(), 2);\n        assert!(clusters.contains(\"c1\"));\n        assert!(clusters.contains(\"c2\"));\n    }\n\n    #[test]\n    fn test_not_all_resources_required() {\n        assert!(!RouteConfigResource::ALL_RESOURCES_REQUIRED_IN_SOTW);\n    }\n\n    #[test]\n    fn test_deserialize_roundtrip() {\n        let rc = make_route_config(\"rc-1\");\n        let bytes = rc.encode_to_vec();\n        let deserialized = RouteConfigResource::deserialize(Bytes::from(bytes)).unwrap();\n        assert_eq!(RouteConfigResource::name(&deserialized), \"rc-1\");\n    }\n\n    #[test]\n    fn test_invalid_regex_fails_validation() {\n        use envoy_types::pb::envoy::config::route::v3::{\n            RouteAction, VirtualHost, route::Action, route_action::ClusterSpecifier,\n        };\n        use envoy_types::pb::envoy::r#type::matcher::v3::RegexMatcher;\n\n        let route = envoy_types::pb::envoy::config::route::v3::Route {\n            r#match: Some(RouteMatch {\n                path_specifier: Some(route_match::PathSpecifier::SafeRegex(RegexMatcher {\n                    regex: \"[invalid\".to_string(),\n                    ..Default::default()\n                })),\n                ..Default::default()\n            }),\n            action: Some(Action::Route(RouteAction {\n                cluster_specifier: Some(ClusterSpecifier::Cluster(\"c1\".to_string())),\n                ..Default::default()\n            })),\n            ..Default::default()\n        };\n        let rc = RouteConfiguration {\n            name: \"rc\".to_string(),\n            virtual_hosts: vec![VirtualHost {\n                name: \"vh1\".to_string(),\n                domains: vec![\"*\".to_string()],\n                routes: vec![route],\n                ..Default::default()\n            }],\n            ..Default::default()\n        };\n        let err = RouteConfigResource::validate(rc).unwrap_err();\n        assert!(err.to_string().contains(\"invalid path regex\"));\n    }\n\n    #[test]\n    fn test_empty_virtual_hosts_fails() {\n        let rc = RouteConfiguration {\n            name: \"rc\".to_string(),\n            virtual_hosts: vec![],\n            ..Default::default()\n        };\n        let err = RouteConfigResource::validate(rc).unwrap_err();\n        assert!(err.to_string().contains(\"no virtual hosts\"));\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/xds/routing.rs",
    "content": "//! Per-request route matching on validated resource types.\n//!\n//! Operates directly on [`RouteConfigResource`] and its sub-types.\n//! The matching pipeline: domain → path → headers.\n//!\n//! Domain matching follows gRFC A27 priority:\n//! 1. Exact match\n//! 2. Suffix wildcard (`*.foo.com`)\n//! 3. Prefix wildcard (`foo.*`)\n//! 4. Universal wildcard `*`\n//!\n//! Within each category, the most specific (longest non-wildcard part) wins.\n\nuse std::cmp::Reverse;\n\nuse crate::xds::resource::route_config::{\n    HeaderMatchSpecifierConfig, HeaderMatcherConfig, PathSpecifierConfig, RouteConfig,\n    RouteConfigAction, RouteConfigMatch, RouteConfigResource, VirtualHostConfig,\n};\n\n/// Error returned when route matching fails.\n#[derive(Debug, Clone, thiserror::Error)]\npub(crate) enum RoutingError {\n    #[error(\"no matching virtual host for authority '{0}'\")]\n    NoMatchingVirtualHost(String),\n    #[error(\"no matching route in virtual host for path '{0}'\")]\n    NoMatchingRoute(String),\n}\n\nimpl RouteConfigResource {\n    /// Match a request and return the target cluster action.\n    ///\n    /// Performs domain matching on the authority, then walks routes in order\n    /// to find the first match.\n    pub(crate) fn route(\n        &self,\n        authority: &str,\n        path: &str,\n        headers: &http::HeaderMap,\n    ) -> Result<&RouteConfigAction, RoutingError> {\n        let vh = find_best_matching_virtual_host(authority, &self.virtual_hosts)\n            .ok_or_else(|| RoutingError::NoMatchingVirtualHost(authority.to_string()))?;\n\n        for route in &vh.routes {\n            if route_matches(route, path, headers) {\n                return Ok(&route.action);\n            }\n        }\n\n        Err(RoutingError::NoMatchingRoute(path.to_string()))\n    }\n}\n\nconst WILDCARD: &str = \"*\";\n\n/// Finds the best-matching virtual host for the given authority.\nfn find_best_matching_virtual_host<'a>(\n    authority: &str,\n    virtual_hosts: &'a [VirtualHostConfig],\n) -> Option<&'a VirtualHostConfig> {\n    virtual_hosts\n        .iter()\n        .filter_map(|vh| {\n            let best_score = vh\n                .domains\n                .iter()\n                .filter_map(|d| match_domain(authority, d))\n                .min()?;\n            Some((best_score, vh))\n        })\n        .min_by_key(|(score, _)| *score)\n        .map(|(_, vh)| vh)\n}\n\n/// How well a domain pattern matched an authority.\n///\n/// Sorts naturally so that better matches are smaller:\n/// match type (Exact < Suffix < Prefix < Universal), then higher\n/// specificity (more non-wildcard characters) breaks ties.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]\nstruct DomainMatchScore(DomainMatchType, Reverse<usize>);\n\n/// Domain match types ordered by priority (lower is better).\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]\nenum DomainMatchType {\n    Exact = 0,\n    Suffix = 1,\n    Prefix = 2,\n    Universal = 3,\n}\n\nfn match_domain(authority: &str, pattern: &str) -> Option<DomainMatchScore> {\n    if pattern == WILDCARD {\n        return Some(DomainMatchScore(DomainMatchType::Universal, Reverse(0)));\n    }\n\n    let authority_lower = authority.to_ascii_lowercase();\n    let pattern_lower = pattern.to_ascii_lowercase();\n\n    if authority_lower == pattern_lower {\n        return Some(DomainMatchScore(\n            DomainMatchType::Exact,\n            Reverse(pattern.len()),\n        ));\n    }\n\n    if let Some(suffix) = pattern_lower.strip_prefix(WILDCARD)\n        && authority_lower.ends_with(suffix)\n        && authority_lower.len() > suffix.len()\n    {\n        return Some(DomainMatchScore(\n            DomainMatchType::Suffix,\n            Reverse(suffix.len()),\n        ));\n    }\n\n    if let Some(prefix) = pattern_lower.strip_suffix(WILDCARD)\n        && authority_lower.starts_with(prefix)\n        && authority_lower.len() > prefix.len()\n    {\n        return Some(DomainMatchScore(\n            DomainMatchType::Prefix,\n            Reverse(prefix.len()),\n        ));\n    }\n\n    None\n}\n\nfn route_matches(route: &RouteConfig, path: &str, headers: &http::HeaderMap) -> bool {\n    match_path(&route.match_criteria, path) && match_headers(&route.match_criteria, headers)\n}\n\nfn match_path(criteria: &RouteConfigMatch, path: &str) -> bool {\n    match &criteria.path_specifier {\n        PathSpecifierConfig::Prefix(prefix) => {\n            if prefix.is_empty() {\n                return true;\n            }\n            if criteria.case_sensitive {\n                path.starts_with(prefix.as_str())\n            } else {\n                path.to_ascii_lowercase()\n                    .starts_with(&prefix.to_ascii_lowercase())\n            }\n        }\n        PathSpecifierConfig::Path(exact) => {\n            if criteria.case_sensitive {\n                path == exact\n            } else {\n                path.eq_ignore_ascii_case(exact)\n            }\n        }\n        PathSpecifierConfig::SafeRegex(re) => re.is_match(path),\n    }\n}\n\nfn match_headers(criteria: &RouteConfigMatch, headers: &http::HeaderMap) -> bool {\n    criteria.headers.iter().all(|m| {\n        let result = match_header(m, headers);\n        if m.invert_match { !result } else { result }\n    })\n}\n\nfn match_header(hm: &HeaderMatcherConfig, headers: &http::HeaderMap) -> bool {\n    let value = headers.get(&hm.name).and_then(|v| v.to_str().ok());\n\n    match &hm.match_specifier {\n        HeaderMatchSpecifierConfig::Present => value.is_some(),\n        HeaderMatchSpecifierConfig::Exact(e) => value.is_some_and(|v| v == e),\n        HeaderMatchSpecifierConfig::Prefix(p) => value.is_some_and(|v| v.starts_with(p.as_str())),\n        HeaderMatchSpecifierConfig::Suffix(s) => value.is_some_and(|v| v.ends_with(s.as_str())),\n        HeaderMatchSpecifierConfig::Contains(c) => value.is_some_and(|v| v.contains(c.as_str())),\n        HeaderMatchSpecifierConfig::SafeRegex(re) => value.is_some_and(|v| re.is_match(v)),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::xds::resource::route_config::{\n        RouteConfig, RouteConfigAction, RouteConfigMatch, VirtualHostConfig,\n    };\n\n    fn simple_route(prefix: &str, cluster: &str) -> RouteConfig {\n        RouteConfig {\n            match_criteria: RouteConfigMatch {\n                path_specifier: PathSpecifierConfig::Prefix(prefix.into()),\n                headers: vec![],\n                case_sensitive: true,\n            },\n            action: RouteConfigAction::Cluster(cluster.into()),\n        }\n    }\n\n    fn simple_rc(virtual_hosts: Vec<VirtualHostConfig>) -> RouteConfigResource {\n        RouteConfigResource {\n            name: \"test-rc\".into(),\n            virtual_hosts,\n        }\n    }\n\n    #[test]\n    fn domain_exact() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"foo.com\".into()],\n            routes: vec![simple_route(\"/\", \"c1\")],\n        }]);\n        assert!(rc.route(\"foo.com\", \"/\", &http::HeaderMap::new()).is_ok());\n    }\n\n    #[test]\n    fn domain_case_insensitive() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"FOO.COM\".into()],\n            routes: vec![simple_route(\"/\", \"c1\")],\n        }]);\n        assert!(rc.route(\"foo.com\", \"/\", &http::HeaderMap::new()).is_ok());\n    }\n\n    #[test]\n    fn domain_suffix_wildcard() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*.foo.com\".into()],\n            routes: vec![simple_route(\"/\", \"c1\")],\n        }]);\n        let h = http::HeaderMap::new();\n        assert!(rc.route(\"bar.foo.com\", \"/\", &h).is_ok());\n        assert!(rc.route(\"foo.com\", \"/\", &h).is_err());\n    }\n\n    #[test]\n    fn domain_prefix_wildcard() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"foo.*\".into()],\n            routes: vec![simple_route(\"/\", \"c1\")],\n        }]);\n        let h = http::HeaderMap::new();\n        assert!(rc.route(\"foo.bar\", \"/\", &h).is_ok());\n        assert!(rc.route(\"bar.foo\", \"/\", &h).is_err());\n    }\n\n    #[test]\n    fn domain_universal() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![simple_route(\"/\", \"c1\")],\n        }]);\n        assert!(\n            rc.route(\"anything.com\", \"/\", &http::HeaderMap::new())\n                .is_ok()\n        );\n    }\n\n    #[test]\n    fn domain_exact_beats_suffix() {\n        let rc = simple_rc(vec![\n            VirtualHostConfig {\n                name: \"vh-suffix\".into(),\n                domains: vec![\"*.foo.com\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-suffix\")],\n            },\n            VirtualHostConfig {\n                name: \"vh-exact\".into(),\n                domains: vec![\"bar.foo.com\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-exact\")],\n            },\n        ]);\n        let action = rc\n            .route(\"bar.foo.com\", \"/\", &http::HeaderMap::new())\n            .unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-exact\"));\n    }\n\n    #[test]\n    fn domain_suffix_beats_universal() {\n        let rc = simple_rc(vec![\n            VirtualHostConfig {\n                name: \"vh-universal\".into(),\n                domains: vec![\"*\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-universal\")],\n            },\n            VirtualHostConfig {\n                name: \"vh-suffix\".into(),\n                domains: vec![\"*.foo.com\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-suffix\")],\n            },\n        ]);\n        let action = rc\n            .route(\"bar.foo.com\", \"/\", &http::HeaderMap::new())\n            .unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-suffix\"));\n    }\n\n    #[test]\n    fn domain_longer_suffix_wins() {\n        let rc = simple_rc(vec![\n            VirtualHostConfig {\n                name: \"vh-short\".into(),\n                domains: vec![\"*.com\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-short\")],\n            },\n            VirtualHostConfig {\n                name: \"vh-long\".into(),\n                domains: vec![\"*.foo.com\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-long\")],\n            },\n        ]);\n        let action = rc\n            .route(\"bar.foo.com\", \"/\", &http::HeaderMap::new())\n            .unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-long\"));\n    }\n\n    #[test]\n    fn domain_no_match() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"foo.com\".into()],\n            routes: vec![simple_route(\"/\", \"c1\")],\n        }]);\n        assert!(rc.route(\"bar.com\", \"/\", &http::HeaderMap::new()).is_err());\n    }\n\n    #[test]\n    fn basic_routing() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![simple_route(\"/\", \"cluster-1\")],\n        }]);\n        let headers = http::HeaderMap::new();\n\n        let action = rc.route(\"any.host\", \"/foo\", &headers).unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-1\"));\n    }\n\n    #[test]\n    fn domain_selects_virtual_host() {\n        let rc = simple_rc(vec![\n            VirtualHostConfig {\n                name: \"vh-foo\".into(),\n                domains: vec![\"foo.com\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-foo\")],\n            },\n            VirtualHostConfig {\n                name: \"vh-bar\".into(),\n                domains: vec![\"bar.com\".into()],\n                routes: vec![simple_route(\"/\", \"cluster-bar\")],\n            },\n        ]);\n        let headers = http::HeaderMap::new();\n\n        let action = rc.route(\"foo.com\", \"/x\", &headers).unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-foo\"));\n\n        let action = rc.route(\"bar.com\", \"/x\", &headers).unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-bar\"));\n    }\n\n    #[test]\n    fn no_matching_virtual_host() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"foo.com\".into()],\n            routes: vec![simple_route(\"/\", \"c1\")],\n        }]);\n        let headers = http::HeaderMap::new();\n\n        let err = rc.route(\"unknown.com\", \"/\", &headers).unwrap_err();\n        assert!(matches!(err, RoutingError::NoMatchingVirtualHost(_)));\n    }\n\n    #[test]\n    fn first_matching_route_wins() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![\n                simple_route(\"/svc/\", \"cluster-svc\"),\n                simple_route(\"/\", \"cluster-default\"),\n            ],\n        }]);\n        let headers = http::HeaderMap::new();\n\n        let action = rc.route(\"host\", \"/svc/Method\", &headers).unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-svc\"));\n\n        let action = rc.route(\"host\", \"/other\", &headers).unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-default\"));\n    }\n\n    #[test]\n    fn no_matching_route() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![simple_route(\"/svc/\", \"c1\")],\n        }]);\n        let headers = http::HeaderMap::new();\n\n        let err = rc.route(\"host\", \"/other\", &headers).unwrap_err();\n        assert!(matches!(err, RoutingError::NoMatchingRoute(_)));\n    }\n\n    #[test]\n    fn exact_path_match() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![RouteConfig {\n                match_criteria: RouteConfigMatch {\n                    path_specifier: PathSpecifierConfig::Path(\"/svc/Method\".into()),\n                    headers: vec![],\n                    case_sensitive: true,\n                },\n                action: RouteConfigAction::Cluster(\"c1\".into()),\n            }],\n        }]);\n        let headers = http::HeaderMap::new();\n\n        assert!(rc.route(\"host\", \"/svc/Method\", &headers).is_ok());\n        assert!(rc.route(\"host\", \"/svc/Other\", &headers).is_err());\n    }\n\n    #[test]\n    fn regex_path_match() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![RouteConfig {\n                match_criteria: RouteConfigMatch {\n                    path_specifier: PathSpecifierConfig::SafeRegex(\n                        regex::Regex::new(\"^/svc/.*\").unwrap(),\n                    ),\n                    headers: vec![],\n                    case_sensitive: true,\n                },\n                action: RouteConfigAction::Cluster(\"c1\".into()),\n            }],\n        }]);\n        let headers = http::HeaderMap::new();\n\n        assert!(rc.route(\"host\", \"/svc/Anything\", &headers).is_ok());\n        assert!(rc.route(\"host\", \"/other\", &headers).is_err());\n    }\n\n    #[test]\n    fn header_matcher_filters_routes() {\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![\n                RouteConfig {\n                    match_criteria: RouteConfigMatch {\n                        path_specifier: PathSpecifierConfig::Prefix(\"/\".into()),\n                        headers: vec![HeaderMatcherConfig {\n                            name: \"x-env\".into(),\n                            match_specifier: HeaderMatchSpecifierConfig::Exact(\"prod\".into()),\n                            invert_match: false,\n                        }],\n                        case_sensitive: true,\n                    },\n                    action: RouteConfigAction::Cluster(\"cluster-prod\".into()),\n                },\n                simple_route(\"/\", \"cluster-default\"),\n            ],\n        }]);\n\n        let mut prod_headers = http::HeaderMap::new();\n        prod_headers.insert(\"x-env\", \"prod\".parse().unwrap());\n        let action = rc.route(\"host\", \"/\", &prod_headers).unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-prod\"));\n\n        let action = rc.route(\"host\", \"/\", &http::HeaderMap::new()).unwrap();\n        assert!(matches!(action, RouteConfigAction::Cluster(c) if c == \"cluster-default\"));\n    }\n\n    #[test]\n    fn weighted_clusters_passed_through() {\n        use crate::xds::resource::route_config::WeightedCluster;\n        let rc = simple_rc(vec![VirtualHostConfig {\n            name: \"vh1\".into(),\n            domains: vec![\"*\".into()],\n            routes: vec![RouteConfig {\n                match_criteria: RouteConfigMatch {\n                    path_specifier: PathSpecifierConfig::Prefix(\"/\".into()),\n                    headers: vec![],\n                    case_sensitive: true,\n                },\n                action: RouteConfigAction::WeightedClusters(vec![\n                    WeightedCluster {\n                        name: \"c1\".into(),\n                        weight: 70,\n                    },\n                    WeightedCluster {\n                        name: \"c2\".into(),\n                        weight: 30,\n                    },\n                ]),\n            }],\n        }]);\n        let action = rc.route(\"host\", \"/\", &http::HeaderMap::new()).unwrap();\n        assert!(matches!(action, RouteConfigAction::WeightedClusters(wcs) if wcs.len() == 2));\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/xds/uri.rs",
    "content": "use thiserror::Error;\nuse url::Url;\n\n/// Error type for parsing xDS URIs.\n#[derive(Debug, Error)]\npub enum XdsUriError {\n    /// The URI scheme is not \"xds\".\n    #[error(\"URI scheme must be 'xds', got '{0}'\")]\n    InvalidScheme(String),\n    /// The URI could not be parsed.\n    #[error(\"invalid URI: {0}\")]\n    InvalidUri(#[from] url::ParseError),\n}\n\n/// An xDS target URI (e.g., `xds:///my-service`).\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct XdsUri {\n    /// The target service name extracted from the URI.\n    pub target: String,\n}\n\nconst XDS_SCHEME: &str = \"xds\";\n\nimpl XdsUri {\n    /// Parses an xDS URI from a string.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if:\n    /// - The URI cannot be parsed as a valid URI ([`XdsUriError::InvalidUri`])\n    /// - The URI scheme is not `xds` ([`XdsUriError::InvalidScheme`])\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tonic_xds::XdsUri;\n    ///\n    /// let uri = XdsUri::parse(\"xds:///my-service\").expect(\"Failed to parse valid xDS URI\");\n    /// assert_eq!(uri.target, \"my-service\");\n    ///\n    /// let invalid_uri = XdsUri::parse(\"http:///my-service\");\n    /// assert!(invalid_uri.is_err());\n    /// assert_eq!(invalid_uri.unwrap_err().to_string(), \"URI scheme must be 'xds', got 'http'\");\n    /// ```\n    pub fn parse(uri: &str) -> Result<Self, XdsUriError> {\n        let uri = Url::parse(uri)?;\n\n        if uri.scheme() != XDS_SCHEME {\n            return Err(XdsUriError::InvalidScheme(uri.scheme().to_string()));\n        }\n\n        let target = uri.path().trim_start_matches('/').to_string();\n\n        Ok(Self { target })\n    }\n}\n"
  },
  {
    "path": "tonic-xds/src/xds/xds_manager.rs",
    "content": "use crate::common::async_util::BoxFuture;\nuse std::pin::Pin;\nuse tower::{BoxError, discover::Change};\n\nuse crate::client::route::{RouteDecision, RouteInput};\n\npub(crate) type BoxDiscover<Endpoint, S> =\n    Pin<Box<dyn futures_core::Stream<Item = Result<Change<Endpoint, S>, BoxError>> + Send>>;\n\n/// Trait for routing requests to clusters based on xDS routing configurations.\npub(crate) trait XdsRouter: Send + Sync + 'static {\n    fn route(&self, input: &RouteInput<'_>) -> BoxFuture<RouteDecision>;\n}\n\n/// Trait for discovering cluster endpoints based on xDS cluster configurations.\npub(crate) trait XdsClusterDiscovery<Endpoint, S>: Send + Sync + 'static {\n    fn discover_cluster(&self, cluster_name: &str) -> BoxDiscover<Endpoint, S>;\n}\n\n/// Combined trait for xDS management (routing + load balancing).\n/// Automatically implemented for any type that implements both `XdsRouter` and `XdsClusterDiscovery`.\n#[allow(dead_code)]\npub(crate) trait XdsManager<Endpoint, S>:\n    XdsRouter + XdsClusterDiscovery<Endpoint, S>\n{\n}\n\nimpl<T, Endpoint, S> XdsManager<Endpoint, S> for T where\n    T: XdsRouter + XdsClusterDiscovery<Endpoint, S>\n{\n}\n"
  },
  {
    "path": "xds-client/Cargo.toml",
    "content": "[package]\nname = \"xds-client\"\ndescription = \"An xDS client implementation in Rust\"\nversion = \"0.1.0-alpha.1\"\nedition = \"2024\"\nhomepage = \"https://github.com/hyperium/tonic\"\nrepository = \"https://github.com/hyperium/tonic\"\nlicense = \"MIT\"\nrust-version = { workspace = true }\npublish = false\n\n[lints]\nworkspace = true\n\n[dependencies]\nbytes = \"1.11.0\"\nthiserror = \"2\"\ntokio = { version = \"1\", features = [\"sync\", \"macros\"] }\n\n# Optional dependencies for tonic transport\ntonic = { version = \"0.14\", optional = true }\ntokio-stream = { version = \"0.1\", optional = true }\nhttp = { version = \"1\", optional = true }\n\n# Optional dependencies for prost codec\nenvoy-types = { version = \"0.7\", optional = true }\nprost = { version = \"0.14\", optional = true }\n\n[features]\ndefault = [\"transport-tonic\", \"codegen-prost\"]\ntransport-tonic = [\n    \"rt-tokio\",\n    \"dep:tonic\",\n    \"dep:tokio-stream\",\n    \"dep:http\",\n]\nrt-tokio = [\"tokio/rt\", \"tokio/time\"]\ncodegen-prost = [\"dep:envoy-types\", \"dep:prost\"]\n\n[dev-dependencies]\ntokio = { version = \"1\", features = [\n    \"rt-multi-thread\",\n    \"macros\",\n    \"net\",\n] }\ntonic = { version = \"0.14\", features = [\"tls-ring\"] }\nasync-stream = \"0.3\"\nenvoy-types = \"0.7\"\nprost = \"0.14\"\n\n[[example]]\nname = \"basic\"\npath = \"examples/basic.rs\"\n\n[package.metadata.cargo_check_external_types]\nallowed_external_types = [\n    # major released\n    \"bytes::*\",\n]\n"
  },
  {
    "path": "xds-client/examples/basic.rs",
    "content": "//! Example demonstrating xds-client usage.\n//!\n//! This example shows:\n//! - How to implement the `Resource` trait for Envoy Listener\n//! - How to create an `XdsClient` with tonic transport and prost codec\n//! - How to watch for resources and handle events\n//!\n//! # Configuration (environment variables)\n//!\n//! - `XDS_SERVER` — URI of the xDS management server (default: `http://localhost:18000`)\n//! - `XDS_LISTENERS` — Comma-separated listener names to watch (required)\n//! - `XDS_CA_CERT` — Path to PEM-encoded CA certificate (enables TLS)\n//! - `XDS_CLIENT_CERT` — Path to PEM-encoded client certificate (for mTLS, requires `XDS_CA_CERT`)\n//! - `XDS_CLIENT_KEY` — Path to PEM-encoded client key (for mTLS, requires `XDS_CLIENT_CERT`)\n//!\n//! # Usage\n//!\n//! ```sh\n//! # Basic usage\n//! XDS_LISTENERS=my-listener cargo run -p xds-client --example basic\n//!\n//! # Multiple listeners\n//! XDS_LISTENERS=listener-1,listener-2 cargo run -p xds-client --example basic\n//!\n//! # Custom server\n//! XDS_SERVER=http://xds.example.com:18000 XDS_LISTENERS=foo cargo run -p xds-client --example basic\n//!\n//! # With TLS\n//! XDS_CA_CERT=/path/to/ca.pem \\\n//!   XDS_CLIENT_CERT=/path/to/client.pem \\\n//!   XDS_CLIENT_KEY=/path/to/client.key \\\n//!   XDS_LISTENERS=my-listener \\\n//!   cargo run -p xds-client --example basic\n//! ```\n\nuse bytes::Bytes;\nuse envoy_types::pb::envoy::config::listener::v3::Listener as ListenerProto;\nuse envoy_types::pb::envoy::extensions::filters::network::http_connection_manager::v3::{\n    HttpConnectionManager, http_connection_manager::RouteSpecifier,\n};\nuse prost::Message;\nuse tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity};\n\nuse xds_client::resource::TypeUrl;\nuse xds_client::{\n    ClientConfig, Node, ProstCodec, Resource, ResourceEvent, Result as XdsResult, ServerConfig,\n    TokioRuntime, TonicTransport, TonicTransportBuilder, TransportBuilder, XdsClient,\n};\n\nstruct Args {\n    server: String,\n    ca_cert: Option<String>,\n    client_cert: Option<String>,\n    client_key: Option<String>,\n    listeners: Vec<String>,\n}\n\nfn parse_args() -> Args {\n    let server =\n        std::env::var(\"XDS_SERVER\").unwrap_or_else(|_| \"http://localhost:18000\".to_string());\n\n    let listeners: Vec<String> = std::env::var(\"XDS_LISTENERS\")\n        .expect(\"XDS_LISTENERS env var is required (comma-separated listener names)\")\n        .split(',')\n        .map(|s| s.trim().to_string())\n        .filter(|s| !s.is_empty())\n        .collect();\n\n    if listeners.is_empty() {\n        panic!(\"XDS_LISTENERS must contain at least one listener name\");\n    }\n\n    let ca_cert = std::env::var(\"XDS_CA_CERT\").ok();\n    let client_cert = std::env::var(\"XDS_CLIENT_CERT\").ok();\n    let client_key = std::env::var(\"XDS_CLIENT_KEY\").ok();\n\n    if client_cert.is_some() && ca_cert.is_none() {\n        panic!(\"XDS_CLIENT_CERT requires XDS_CA_CERT to be set\");\n    }\n    if client_key.is_some() && client_cert.is_none() {\n        panic!(\"XDS_CLIENT_KEY requires XDS_CLIENT_CERT to be set\");\n    }\n\n    Args {\n        server,\n        ca_cert,\n        client_cert,\n        client_key,\n        listeners,\n    }\n}\n\n/// A simplified Listener resource for gRPC xDS.\n///\n/// Extracts the RDS route config name from the ApiListener's HttpConnectionManager.\n#[derive(Debug, Clone)]\npub struct Listener {\n    /// The listener name.\n    pub name: String,\n    /// The RDS route config name (from HttpConnectionManager).\n    pub rds_route_config_name: Option<String>,\n}\n\n/// Custom transport builder that configures TLS on the channel.\n///\n/// This demonstrates how to implement a custom [`TransportBuilder`] when you need\n/// TLS or other custom channel configuration. The default [`TonicTransportBuilder`]\n/// creates plain (non-TLS) connections.\nstruct TlsTransportBuilder {\n    tls_config: ClientTlsConfig,\n}\n\nimpl TransportBuilder for TlsTransportBuilder {\n    type Transport = TonicTransport;\n\n    async fn build(&self, server: &ServerConfig) -> XdsResult<Self::Transport> {\n        let channel = Channel::from_shared(server.uri().to_string())\n            .map_err(|e| xds_client::Error::Connection(e.to_string()))?\n            .tls_config(self.tls_config.clone())\n            .map_err(|e| xds_client::Error::Connection(e.to_string()))?\n            .connect()\n            .await\n            .map_err(|e| xds_client::Error::Connection(e.to_string()))?;\n\n        Ok(TonicTransport::from_channel(channel))\n    }\n}\n\nimpl Resource for Listener {\n    type Message = ListenerProto;\n\n    const TYPE_URL: TypeUrl = TypeUrl::new(\"type.googleapis.com/envoy.config.listener.v3.Listener\");\n\n    fn deserialize(bytes: Bytes) -> xds_client::Result<Self::Message> {\n        ListenerProto::decode(bytes).map_err(Into::into)\n    }\n\n    fn name(message: &Self::Message) -> &str {\n        &message.name\n    }\n\n    fn validate(message: Self::Message) -> xds_client::Result<Self> {\n        let hcm = message\n            .api_listener\n            .and_then(|api| api.api_listener)\n            .and_then(|any| HttpConnectionManager::decode(Bytes::from(any.value)).ok());\n\n        let rds_route_config_name = hcm.and_then(|hcm| match hcm.route_specifier {\n            Some(RouteSpecifier::Rds(rds)) => Some(rds.route_config_name),\n            _ => None,\n        });\n\n        Ok(Self {\n            name: message.name,\n            rds_route_config_name,\n        })\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let args = parse_args();\n\n    println!(\"xds-client Example\\n\");\n    println!(\"Connecting to xDS server: {}\", args.server);\n\n    let node = Node::new(\"grpc\", \"1.0\").with_id(\"example-node\");\n    let config = ClientConfig::new(node, &args.server);\n\n    let client = match &args.ca_cert {\n        Some(ca_path) => {\n            let ca_cert = std::fs::read_to_string(ca_path)?;\n            let mut tls = ClientTlsConfig::new().ca_certificate(Certificate::from_pem(&ca_cert));\n\n            if let (Some(cert_path), Some(key_path)) = (&args.client_cert, &args.client_key) {\n                let client_cert = std::fs::read_to_string(cert_path)?;\n                let client_key = std::fs::read_to_string(key_path)?;\n                tls = tls.identity(Identity::from_pem(client_cert, client_key));\n            }\n\n            let tls_builder = TlsTransportBuilder { tls_config: tls };\n            XdsClient::builder(config, tls_builder, ProstCodec, TokioRuntime).build()\n        }\n        None => XdsClient::builder(\n            config,\n            TonicTransportBuilder::new(),\n            ProstCodec,\n            TokioRuntime,\n        )\n        .build(),\n    };\n\n    println!(\"Starting watchers...\\n\");\n\n    let (event_tx, mut event_rx) =\n        tokio::sync::mpsc::unbounded_channel::<ResourceEvent<Listener>>();\n\n    // Start watchers for each listener from args\n    for name in &args.listeners {\n        println!(\"Watching for Listener: '{name}'\");\n\n        let mut watcher = client.watch::<Listener>(name).await;\n        let tx = event_tx.clone();\n\n        tokio::spawn(async move {\n            while let Some(event) = watcher.next().await {\n                if tx.send(event).is_err() {\n                    eprintln!(\"Event channel closed, stopping watcher\");\n                    break;\n                }\n            }\n        });\n    }\n\n    // Drop the original sender so the loop exits when all watchers complete\n    drop(event_tx);\n\n    while let Some(event) = event_rx.recv().await {\n        match event {\n            ResourceEvent::ResourceChanged {\n                result: Ok(resource),\n                done,\n            } => {\n                println!(\"Listener received:\");\n                println!(\"  name:        {}\", resource.name);\n                if let Some(ref rds) = resource.rds_route_config_name {\n                    println!(\"  rds_config:  {rds}\");\n                }\n                println!();\n\n                // In gRPC xDS, you would cascadingly subscribe to RDS, CDS, EDS, etc.\n                // The done signal is sent automatically when it's dropped.\n                drop(done);\n            }\n\n            ResourceEvent::ResourceChanged {\n                result: Err(error), ..\n            } => {\n                // Resource was invalidated (validation error, deleted, etc.)\n                println!(\"Resource invalidated: {error}\");\n            }\n\n            ResourceEvent::AmbientError { error, .. } => {\n                // Non-fatal error, continue using cached resource if available\n                println!(\"Ambient error: {error}\");\n            }\n        }\n    }\n\n    println!(\"Exiting\");\n    Ok(())\n}\n"
  },
  {
    "path": "xds-client/src/client/config.rs",
    "content": "//! Configuration for the xDS client.\n\nuse std::time::Duration;\n\nuse crate::client::retry::RetryPolicy;\nuse crate::message::Node;\n\n/// Configuration for an xDS management server.\n#[derive(Debug, Clone)]\n#[non_exhaustive]\npub struct ServerConfig {\n    uri: String,\n    // Future extensions per gRFC:\n    // - `ignore_resource_deletion: bool` (gRFC A53)\n    // - Server features / capabilities\n    // - Per-server channel credentials config\n}\n\nimpl ServerConfig {\n    /// Create a new server configuration with the given URI.\n    pub fn new(uri: impl Into<String>) -> Self {\n        Self { uri: uri.into() }\n    }\n\n    /// Returns the URI of the management server.\n    pub fn uri(&self) -> &str {\n        &self.uri\n    }\n}\n\n/// Default timeout for initial resource response (30 seconds per gRFC A57).\npub const DEFAULT_RESOURCE_INITIAL_TIMEOUT: Duration = Duration::from_secs(30);\n\n/// Configuration for the xDS client.\n#[derive(Debug, Clone)]\n#[non_exhaustive]\npub struct ClientConfig {\n    /// Node identification sent to the xDS server.\n    pub(crate) node: Node,\n\n    /// Retry policy for connection attempts.\n    ///\n    /// Controls the backoff behavior when reconnecting to the xDS server.\n    pub(crate) retry_policy: RetryPolicy,\n\n    /// Priority-ordered list of xDS management servers.\n    ///\n    /// The client will attempt to connect to servers in order, falling back\n    /// to the next server if the current one is unavailable (per gRFC A71).\n    /// Index 0 has the highest priority.\n    pub(crate) servers: Vec<ServerConfig>,\n\n    /// Timeout for initial resource response (gRFC A57).\n    ///\n    /// If a watched resource is not received within this duration after the watch\n    /// is registered, watchers receive a `ResourceDoesNotExist` error.\n    ///\n    /// Default: 30 seconds. Set to `None` to disable the timeout.\n    pub(crate) resource_initial_timeout: Option<Duration>,\n    // Future extensions:\n    // - `authorities: HashMap<String, AuthorityConfig>` for xDS federation (gRFC A47)\n    // - Locality / zone information for locality-aware routing\n}\n\nimpl ClientConfig {\n    /// Create a new configuration with a single server.\n    ///\n    /// Uses the default retry policy.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use xds_client::{ClientConfig, Node};\n    ///\n    /// let node = Node::new(\"grpc\", \"1.0\")\n    ///     .with_id(\"my-node\")\n    ///     .with_cluster(\"my-cluster\");\n    ///\n    /// let config = ClientConfig::new(node, \"https://xds.example.com:443\");\n    /// ```\n    pub fn new(node: Node, server_uri: impl Into<String>) -> Self {\n        Self {\n            node,\n            retry_policy: RetryPolicy::default(),\n            servers: vec![ServerConfig::new(server_uri)],\n            resource_initial_timeout: Some(DEFAULT_RESOURCE_INITIAL_TIMEOUT),\n        }\n    }\n\n    /// Create a new configuration with multiple servers for fallback.\n    ///\n    /// Servers are tried in order; index 0 has the highest priority.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use xds_client::{ClientConfig, Node, ServerConfig};\n    ///\n    /// let node = Node::new(\"grpc\", \"1.0\");\n    /// let config = ClientConfig::with_servers(node, vec![\n    ///     ServerConfig::new(\"https://primary.xds.example.com:443\"),\n    ///     ServerConfig::new(\"https://backup.xds.example.com:443\"),\n    /// ]);\n    /// ```\n    pub fn with_servers(node: Node, servers: Vec<ServerConfig>) -> Self {\n        Self {\n            node,\n            retry_policy: RetryPolicy::default(),\n            servers,\n            resource_initial_timeout: Some(DEFAULT_RESOURCE_INITIAL_TIMEOUT),\n        }\n    }\n\n    /// Set the retry policy.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use xds_client::{ClientConfig, Node, RetryPolicy};\n    /// use std::time::Duration;\n    ///\n    /// let node = Node::new(\"grpc\", \"1.0\");\n    /// let policy = RetryPolicy::default()\n    ///     .with_initial_backoff(Duration::from_millis(500)).unwrap()\n    ///     .with_max_backoff(Duration::from_secs(60)).unwrap();\n    ///\n    /// let config = ClientConfig::new(node, \"https://xds.example.com:443\")\n    ///     .with_retry_policy(policy);\n    /// ```\n    pub fn with_retry_policy(mut self, policy: RetryPolicy) -> Self {\n        self.retry_policy = policy;\n        self\n    }\n\n    /// Set the timeout for initial resource response (gRFC A57).\n    ///\n    /// If a watched resource is not received within this duration after the watch\n    /// is registered, watchers receive a `ResourceDoesNotExist` error.\n    ///\n    /// Set to `None` to disable the timeout.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use xds_client::{ClientConfig, Node};\n    /// use std::time::Duration;\n    ///\n    /// let node = Node::new(\"grpc\", \"1.0\");\n    ///\n    /// // Use a custom timeout\n    /// let config = ClientConfig::new(node.clone(), \"https://xds.example.com:443\")\n    ///     .with_resource_initial_timeout(Some(Duration::from_secs(60)));\n    ///\n    /// // Disable the timeout\n    /// let config = ClientConfig::new(node, \"https://xds.example.com:443\")\n    ///     .with_resource_initial_timeout(None);\n    /// ```\n    pub fn with_resource_initial_timeout(mut self, timeout: Option<Duration>) -> Self {\n        self.resource_initial_timeout = timeout;\n        self\n    }\n}\n"
  },
  {
    "path": "xds-client/src/client/mod.rs",
    "content": "//! Client interface through which the user can watch and receive updates for xDS resources.\n\nuse tokio::sync::mpsc;\n\nuse crate::client::config::ClientConfig;\nuse crate::client::watch::ResourceWatcher;\nuse crate::client::worker::{AdsWorker, WatcherId, WorkerCommand};\nuse crate::codec::XdsCodec;\nuse crate::resource::{DecodedResource, DecoderFn, Resource};\nuse crate::runtime::Runtime;\nuse crate::transport::TransportBuilder;\n\npub mod config;\npub mod retry;\npub mod watch;\npub mod worker;\n\n/// Builder for [`XdsClient`].\n#[derive(Debug)]\npub struct XdsClientBuilder<TB, C, R> {\n    config: ClientConfig,\n    transport_builder: TB,\n    codec: C,\n    runtime: R,\n}\n\nimpl<TB, C, R> XdsClientBuilder<TB, C, R>\nwhere\n    TB: TransportBuilder,\n    C: XdsCodec,\n    R: Runtime,\n{\n    /// Create a new builder with the given configuration, transport builder, codec, and runtime.\n    pub fn new(config: ClientConfig, transport_builder: TB, codec: C, runtime: R) -> Self {\n        Self {\n            config,\n            transport_builder,\n            codec,\n            runtime,\n        }\n    }\n\n    /// Build the client and start the background worker.\n    ///\n    /// This spawns a background task that manages the ADS stream.\n    /// The task runs until all `XdsClient` handles are dropped.\n    pub fn build(self) -> XdsClient {\n        let (command_tx, command_rx) = mpsc::channel(COMMAND_CHANNEL_BUFFER_SIZE);\n\n        let worker = AdsWorker::new(\n            self.transport_builder,\n            self.codec,\n            self.runtime.clone(),\n            self.config,\n            command_tx.clone(),\n            command_rx,\n        );\n\n        self.runtime.spawn(async move {\n            worker.run().await;\n        });\n\n        XdsClient { command_tx }\n    }\n}\n\n/// The xDS client.\n///\n/// This is a handle to the background worker that manages the ADS stream.\n/// Cloning this handle creates a new reference to the same worker.\n///\n/// When all `XdsClient` handles are dropped, the background worker shuts down.\n#[derive(Clone, Debug)]\npub struct XdsClient {\n    /// Channel to send commands to the worker.\n    command_tx: mpsc::Sender<WorkerCommand>,\n}\n\n/// Buffer size for the command channel between [`XdsClient`] handles and the worker.\n///\n/// Commands are lightweight (watch/unwatch/timer), so a modest buffer suffices.\n/// The channel provides backpressure if the worker is temporarily busy processing\n/// a response.\nconst COMMAND_CHANNEL_BUFFER_SIZE: usize = 64;\n\n/// Default buffer size for watcher event channels.\n///\n/// This provides backpressure when watchers are slow to process events.\nconst WATCHER_CHANNEL_BUFFER_SIZE: usize = 16;\n\nimpl XdsClient {\n    /// Create a new builder with the given configuration, transport builder, codec, and runtime.\n    pub fn builder<TB, C, R>(\n        config: ClientConfig,\n        transport_builder: TB,\n        codec: C,\n        runtime: R,\n    ) -> XdsClientBuilder<TB, C, R>\n    where\n        TB: TransportBuilder,\n        C: XdsCodec,\n        R: Runtime,\n    {\n        XdsClientBuilder::new(config, transport_builder, codec, runtime)\n    }\n\n    /// Watch a resource by name.\n    ///\n    /// Returns a [`ResourceWatcher`] that receives events for this resource.\n    /// Dropping the watcher automatically unsubscribes.\n    ///\n    /// # Arguments\n    ///\n    /// * `name` - The resource name to watch. Use an empty string for wildcard\n    ///   subscriptions (receive all resources of this type).\n    ///\n    /// # Example\n    ///\n    /// ```ignore\n    /// let mut watcher = client.watch::<Listener>(\"my-listener\").await;\n    /// while let Some(event) = watcher.next().await {\n    ///     match event {\n    ///         ResourceEvent::ResourceChanged { result: Ok(resource), done } => {\n    ///             println!(\"Listener changed: {}\", resource.name());\n    ///             // Signal is sent automatically when done is dropped\n    ///         }\n    ///         ResourceEvent::ResourceChanged { result: Err(error), .. } => {\n    ///             println!(\"Error watching listener: {}\", error);\n    ///         }\n    ///         ResourceEvent::AmbientError { error, .. } => {\n    ///             println!(\"Ambient error: {}\", error);\n    ///         }\n    ///     }\n    /// }\n    /// ```\n    pub async fn watch<T: Resource>(&self, name: impl Into<String>) -> ResourceWatcher<T> {\n        let name = name.into();\n        let watcher_id = WatcherId::new();\n        let (event_tx, event_rx) = mpsc::channel(WATCHER_CHANNEL_BUFFER_SIZE);\n\n        let decoder: DecoderFn = Box::new(|bytes| match crate::resource::decode::<T>(bytes) {\n            crate::resource::DecodeResult::Success { name, resource } => {\n                crate::resource::DecodeResult::Success {\n                    name: name.clone(),\n                    resource: DecodedResource::new(name, resource),\n                }\n            }\n            crate::resource::DecodeResult::ResourceError { name, error } => {\n                crate::resource::DecodeResult::ResourceError { name, error }\n            }\n            crate::resource::DecodeResult::TopLevelError(error) => {\n                crate::resource::DecodeResult::TopLevelError(error)\n            }\n        });\n\n        let _ = self\n            .command_tx\n            .send(WorkerCommand::Watch {\n                type_url: T::TYPE_URL.as_str(),\n                name,\n                watcher_id,\n                event_tx,\n                decoder,\n                all_resources_required_in_sotw: T::ALL_RESOURCES_REQUIRED_IN_SOTW,\n            })\n            .await;\n\n        ResourceWatcher::new(event_rx, watcher_id, self.command_tx.clone())\n    }\n}\n"
  },
  {
    "path": "xds-client/src/client/retry.rs",
    "content": "//! Retry policy configuration based on gRFC A6.\n\nuse std::time::Duration;\n\nuse crate::error::{Error, Result};\n\n/// Retry policy for xDS client connection attempts.\n///\n/// This configuration follows the gRFC A6 proposal for client retries,\n/// using exponential backoff with jitter for reconnection attempts.\n///\n/// # Example\n///\n/// ```\n/// use xds_client::RetryPolicy;\n/// use std::time::Duration;\n///\n/// let policy = RetryPolicy::default()\n///     .with_initial_backoff(Duration::from_secs(1)).unwrap()\n///     .with_max_backoff(Duration::from_secs(30)).unwrap()\n///     .with_backoff_multiplier(2.0).unwrap();\n/// ```\n#[derive(Debug, Clone)]\npub struct RetryPolicy {\n    /// Initial backoff duration for the first retry attempt.\n    ///\n    /// Default: 1 second.\n    pub initial_backoff: Duration,\n\n    /// Maximum backoff duration.\n    ///\n    /// The backoff will not grow beyond this value, regardless of how many\n    /// retry attempts have been made.\n    ///\n    /// Default: 30 seconds.\n    pub max_backoff: Duration,\n\n    /// Multiplier for exponential backoff.\n    ///\n    /// After each failed attempt, the current backoff duration is multiplied\n    /// by this value (up to `max_backoff`).\n    ///\n    /// Default: 2.0 (exponential backoff).\n    pub backoff_multiplier: f64,\n\n    /// Maximum number of retry attempts.\n    ///\n    /// If `None`, retries indefinitely. If `Some(n)`, stops after `n` attempts.\n    ///\n    /// Default: None (infinite retries).\n    pub max_attempts: Option<usize>,\n}\n\nimpl RetryPolicy {\n    /// Create a new retry policy with custom parameters.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if:\n    /// - `backoff_multiplier` is less than 1.0\n    /// - `max_backoff` is less than `initial_backoff`\n    /// - `initial_backoff` is zero\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use xds_client::RetryPolicy;\n    /// use std::time::Duration;\n    ///\n    /// let policy = RetryPolicy::new(\n    ///     Duration::from_millis(500),  // initial_backoff\n    ///     Duration::from_secs(60),     // max_backoff\n    ///     1.5,                         // backoff_multiplier\n    /// )?;\n    /// # Ok::<(), xds_client::Error>(())\n    /// ```\n    pub fn new(\n        initial_backoff: Duration,\n        max_backoff: Duration,\n        backoff_multiplier: f64,\n    ) -> Result<Self> {\n        if initial_backoff.is_zero() {\n            return Err(Error::Validation(\n                \"initial_backoff must be greater than zero\".into(),\n            ));\n        }\n\n        if backoff_multiplier < 1.0 {\n            return Err(Error::Validation(format!(\n                \"backoff_multiplier must be >= 1.0, got {backoff_multiplier}\"\n            )));\n        }\n\n        if max_backoff < initial_backoff {\n            return Err(Error::Validation(format!(\n                \"max_backoff ({max_backoff:?}) must be >= initial_backoff ({initial_backoff:?})\"\n            )));\n        }\n\n        Ok(Self {\n            initial_backoff,\n            max_backoff,\n            backoff_multiplier,\n            max_attempts: None,\n        })\n    }\n\n    /// Set the initial backoff duration.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if `duration` is zero or greater than `max_backoff`.\n    pub fn with_initial_backoff(mut self, duration: Duration) -> Result<Self> {\n        if duration.is_zero() {\n            return Err(Error::Validation(\n                \"initial_backoff must be greater than zero\".into(),\n            ));\n        }\n        if duration > self.max_backoff {\n            let max_backoff = self.max_backoff;\n            return Err(Error::Validation(format!(\n                \"initial_backoff ({duration:?}) must be <= max_backoff ({max_backoff:?})\"\n            )));\n        }\n        self.initial_backoff = duration;\n        Ok(self)\n    }\n\n    /// Set the maximum backoff duration.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if `duration` is less than `initial_backoff`.\n    pub fn with_max_backoff(mut self, duration: Duration) -> Result<Self> {\n        if duration < self.initial_backoff {\n            let initial_backoff = self.initial_backoff;\n            return Err(Error::Validation(format!(\n                \"max_backoff ({duration:?}) must be >= initial_backoff ({initial_backoff:?})\"\n            )));\n        }\n        self.max_backoff = duration;\n        Ok(self)\n    }\n\n    /// Set the backoff multiplier.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if `multiplier` is less than 1.0.\n    pub fn with_backoff_multiplier(mut self, multiplier: f64) -> Result<Self> {\n        if multiplier < 1.0 {\n            return Err(Error::Validation(format!(\n                \"backoff_multiplier must be >= 1.0, got {multiplier}\"\n            )));\n        }\n        self.backoff_multiplier = multiplier;\n        Ok(self)\n    }\n\n    /// Set the maximum number of retry attempts.\n    ///\n    /// If set to `None`, retries indefinitely.\n    pub fn with_max_attempts(mut self, max_attempts: Option<usize>) -> Self {\n        self.max_attempts = max_attempts;\n        self\n    }\n\n    /// Calculate the backoff duration for a given attempt number.\n    ///\n    /// Returns `None` if `max_attempts` is set and the attempt exceeds it.\n    ///\n    /// # Arguments\n    ///\n    /// * `attempt` - The retry attempt number (0-indexed).\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use xds_client::RetryPolicy;\n    /// use std::time::Duration;\n    ///\n    /// let policy = RetryPolicy::default();\n    /// assert_eq!(policy.backoff_duration(0), Some(Duration::from_secs(1)));\n    /// assert_eq!(policy.backoff_duration(1), Some(Duration::from_secs(2)));\n    /// assert_eq!(policy.backoff_duration(2), Some(Duration::from_secs(4)));\n    /// ```\n    pub fn backoff_duration(&self, attempt: usize) -> Option<Duration> {\n        // Check if we've exceeded max attempts\n        if let Some(max) = self.max_attempts\n            && attempt >= max\n        {\n            return None;\n        }\n\n        // Calculate exponential backoff (saturate to i32::MAX to avoid overflow in powi)\n        let exponent = i32::try_from(attempt).unwrap_or(i32::MAX);\n        let multiplier = self.backoff_multiplier.powi(exponent);\n        let backoff = self.initial_backoff.mul_f64(multiplier);\n\n        // Cap at max_backoff\n        Some(backoff.min(self.max_backoff))\n    }\n}\n\nimpl Default for RetryPolicy {\n    /// Create a retry policy with default values based on gRFC A6.\n    ///\n    /// Defaults:\n    /// - `initial_backoff`: 1 second\n    /// - `max_backoff`: 30 seconds\n    /// - `backoff_multiplier`: 2.0\n    /// - `max_attempts`: None (infinite retries)\n    fn default() -> Self {\n        Self {\n            initial_backoff: Duration::from_secs(1),\n            max_backoff: Duration::from_secs(30),\n            backoff_multiplier: 2.0,\n            max_attempts: None,\n        }\n    }\n}\n\n/// Stateful backoff calculator based on a [`RetryPolicy`].\n///\n/// This struct tracks the current attempt number and provides methods to\n/// get the next backoff duration and reset after successful operations.\n///\n/// # Example\n///\n/// ```\n/// use xds_client::{Backoff, RetryPolicy};\n/// use std::time::Duration;\n///\n/// let mut backoff = Backoff::new(RetryPolicy::default());\n///\n/// // First failure: get initial backoff\n/// assert_eq!(backoff.next_backoff(), Some(Duration::from_secs(1)));\n///\n/// // Second failure: backoff doubles\n/// assert_eq!(backoff.next_backoff(), Some(Duration::from_secs(2)));\n///\n/// // Success: reset for next failure sequence\n/// backoff.reset();\n/// assert_eq!(backoff.next_backoff(), Some(Duration::from_secs(1)));\n/// ```\n#[derive(Debug, Clone)]\npub struct Backoff {\n    policy: RetryPolicy,\n    attempt: usize,\n}\n\nimpl Backoff {\n    /// Create a new backoff calculator from a retry policy.\n    pub fn new(policy: RetryPolicy) -> Self {\n        Self { policy, attempt: 0 }\n    }\n\n    /// Get the next backoff duration and advance the attempt counter.\n    ///\n    /// Returns `None` if `max_attempts` is set and has been exceeded.\n    pub fn next_backoff(&mut self) -> Option<Duration> {\n        let duration = self.policy.backoff_duration(self.attempt)?;\n        self.attempt += 1;\n        Some(duration)\n    }\n\n    /// Reset the backoff after a successful operation.\n    ///\n    /// This resets the attempt counter to 0, so the next failure will\n    /// use the initial backoff duration.\n    pub fn reset(&mut self) {\n        self.attempt = 0;\n    }\n}\n"
  },
  {
    "path": "xds-client/src/client/watch.rs",
    "content": "//! Resource watcher types.\n\nuse std::marker::PhantomData;\nuse std::sync::Arc;\n\nuse tokio::sync::{mpsc, oneshot};\n\nuse crate::client::worker::{WatcherId, WorkerCommand};\nuse crate::error::Error;\nuse crate::resource::{DecodedResource, Resource};\n\n/// A signal to indicate that processing of a resource event is complete.\n///\n/// The xDS client waits for this signal before sending ACK/NACK to the server.\n/// This allows watchers to add cascading subscriptions (e.g. LDS -> RDS -> CDS -> EDS)\n/// that will be included in the same ACK.\n///\n/// # Automatic Signaling\n///\n/// Signals automatically when dropped. If you have cascading watches to add, simply\n/// add them before dropping the `ProcessingDone`.\n///\n/// # Example\n///\n/// ```ignore\n/// match event {\n///     ResourceEvent::ResourceChanged { result: Ok(resource), done } => {\n///         // Process the new resource, possibly add cascading watches.\n///         client.watch::<RouteConfiguration>(&resource.route_name()).await;\n///         // Signal is sent automatically when done is dropped\n///     }\n///     ResourceEvent::ResourceChanged { result: Err(error), done } => {\n///         // Resource was invalidated (validation error or deleted)\n///         eprintln!(\"Resource invalidated: {}\", error);\n///         // Stop using the previously cached resource\n///     }\n///     ResourceEvent::AmbientError { error, .. } => {\n///         // Non-fatal error, continue using cached resource\n///         eprintln!(\"Ambient error: {}\", error);\n///     }\n/// }\n/// ```\n#[derive(Debug)]\npub struct ProcessingDone(Option<oneshot::Sender<()>>);\n\nimpl ProcessingDone {\n    /// Create a channel pair for signaling.\n    ///\n    /// Returns the `ProcessingDone` sender and a receiver future that resolves\n    /// when the sender is dropped.\n    pub(crate) fn channel() -> (Self, oneshot::Receiver<()>) {\n        let (tx, rx) = oneshot::channel();\n        (Self(Some(tx)), rx)\n    }\n}\n\nimpl Drop for ProcessingDone {\n    fn drop(&mut self) {\n        // Auto-signal on drop to prevent deadlocks.\n        if let Some(tx) = self.0.take() {\n            let _ = tx.send(());\n        }\n    }\n}\n\n/// Events delivered to resource watchers.\n///\n/// Per gRFC A88, there are two types of events:\n/// - `ResourceChanged`: Indicates a change in the resource's cached state\n/// - `AmbientError`: Non-fatal errors that don't affect the cached resource\n#[derive(Debug)]\npub enum ResourceEvent<T> {\n    /// Indicates a change in the resource's cached state.\n    ///\n    /// This event is sent when:\n    /// - A new valid resource is received (`Ok(resource)`)\n    /// - A validation error occurred (`Err(Error::Validation(...))`)\n    /// - The resource was deleted or doesn't exist (`Err(Error::ResourceDoesNotExist)`)\n    ///\n    /// When `result` is `Err`, the previously cached resource (if any) should be\n    /// invalidated. The watcher should stop using the old resource data.\n    ///\n    /// The resource is wrapped in `Arc` because multiple watchers may\n    /// subscribe to the same resource and share the same data.\n    ResourceChanged {\n        /// The result of the resource update.\n        /// - `Ok(resource)`: New valid resource received\n        /// - `Err(error)`: Cache-invalidating error (validation failure, does not exist)\n        result: Result<Arc<T>, Error>,\n        /// Signal when processing is complete.\n        done: ProcessingDone,\n    },\n    /// Indicates a non-fatal error that doesn't affect the cached resource.\n    ///\n    /// This is sent for transient errors like temporary connectivity issues\n    /// with the xDS management server. The previously cached resource (if any)\n    /// should continue to be used.\n    ///\n    /// Per gRFC A88, ambient errors should not cause the client to stop using\n    /// a previously valid resource.\n    AmbientError {\n        /// The error that occurred.\n        error: Error,\n        /// Signal when processing is complete.\n        done: ProcessingDone,\n    },\n}\n\n/// A watcher for resources of type `T`.\n///\n/// Call [`next()`](Self::next) to receive resource events.\n/// Dropping the watcher unsubscribes from the resource.\n#[derive(Debug)]\npub struct ResourceWatcher<T: Resource> {\n    /// Channel to receive events from the worker.\n    event_rx: mpsc::Receiver<ResourceEvent<DecodedResource>>,\n    /// Unique identifier for this watcher.\n    watcher_id: WatcherId,\n    /// Channel to send commands to the worker (for unwatch on drop).\n    command_tx: mpsc::Sender<WorkerCommand>,\n    /// Marker for the resource type.\n    _marker: PhantomData<T>,\n}\n\nimpl<T: Resource> ResourceWatcher<T> {\n    /// Create a new resource watcher.\n    pub(crate) fn new(\n        event_rx: mpsc::Receiver<ResourceEvent<DecodedResource>>,\n        watcher_id: WatcherId,\n        command_tx: mpsc::Sender<WorkerCommand>,\n    ) -> Self {\n        Self {\n            event_rx,\n            watcher_id,\n            command_tx,\n            _marker: PhantomData,\n        }\n    }\n\n    /// Returns the next resource event.\n    ///\n    /// Returns `None` when the subscription is closed (worker shut down).\n    ///\n    /// # Example\n    ///\n    /// ```ignore\n    /// while let Some(event) = watcher.next().await {\n    ///     match event {\n    ///         ResourceEvent::ResourceChanged { result: Ok(resource), done } => {\n    ///             // Process the new resource, possibly add cascading watches.\n    ///             client.watch::<RouteConfiguration>(&resource.route_name()).await;\n    ///             // Signal is sent automatically when done is dropped\n    ///         }\n    ///         ResourceEvent::ResourceChanged { result: Err(error), done } => {\n    ///             // Resource was invalidated (validation error or deleted)\n    ///             eprintln!(\"Resource invalidated: {}\", error);\n    ///         }\n    ///         ResourceEvent::AmbientError { error, .. } => {\n    ///             // Non-fatal error, continue using cached resource\n    ///             eprintln!(\"Ambient error: {}\", error);\n    ///         }\n    ///     }\n    /// }\n    /// ```\n    pub async fn next(&mut self) -> Option<ResourceEvent<T>> {\n        let event = self.event_rx.recv().await?;\n\n        Some(match event {\n            ResourceEvent::ResourceChanged { result, done } => {\n                let typed_result = match result {\n                    Ok(resource) => match resource.downcast::<T>() {\n                        Some(typed_resource) => Ok(typed_resource),\n                        None => Err(Error::Validation(format!(\n                            \"resource type mismatch (expected: {}, actual: {})\",\n                            std::any::type_name::<T>(),\n                            resource.type_url()\n                        ))),\n                    },\n                    Err(e) => Err(e),\n                };\n                ResourceEvent::ResourceChanged {\n                    result: typed_result,\n                    done,\n                }\n            }\n            ResourceEvent::AmbientError { error, done } => {\n                ResourceEvent::AmbientError { error, done }\n            }\n        })\n    }\n}\n\nimpl<T: Resource> Drop for ResourceWatcher<T> {\n    fn drop(&mut self) {\n        // Best-effort: if the channel is full or closed, the worker will\n        // detect the closed event channel and clean up the watcher eventually.\n        let _ = self.command_tx.try_send(WorkerCommand::Unwatch {\n            watcher_id: self.watcher_id,\n        });\n    }\n}\n"
  },
  {
    "path": "xds-client/src/client/worker.rs",
    "content": "//! ADS worker that manages the xDS stream.\n//!\n//! The worker runs as a background task, managing:\n//! - The ADS stream lifecycle (connection, reconnection)\n//! - Resource subscriptions and version/nonce tracking\n//! - Dispatching resources to watchers\n//! - ACK/NACK protocol\n\nuse std::collections::{HashMap, HashSet};\nuse std::sync::Arc;\nuse std::sync::atomic::{AtomicU64, Ordering};\nuse std::time::Duration;\n\nuse bytes::Bytes;\nuse tokio::sync::{mpsc, oneshot};\n\nuse crate::client::config::{ClientConfig, ServerConfig};\nuse crate::client::retry::Backoff;\nuse crate::client::watch::{ProcessingDone, ResourceEvent};\nuse crate::codec::XdsCodec;\nuse crate::error::{Error, Result};\nuse crate::message::{DiscoveryRequest, DiscoveryResponse, ErrorDetail, Node};\nuse crate::resource::{DecodedResource, DecoderFn};\nuse crate::runtime::Runtime;\nuse crate::transport::{Transport, TransportBuilder, TransportStream};\n\n/// Global counter for generating unique watcher IDs.\nstatic NEXT_WATCHER_ID: AtomicU64 = AtomicU64::new(1);\n\n/// Unique identifier for a watcher.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub struct WatcherId(u64);\n\nimpl WatcherId {\n    /// Create a new unique watcher ID.\n    pub fn new() -> Self {\n        Self(NEXT_WATCHER_ID.fetch_add(1, Ordering::Relaxed))\n    }\n}\n\nimpl Default for WatcherId {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// Commands sent from `XdsClient` to the worker.\npub(crate) enum WorkerCommand {\n    /// Subscribe to a resource.\n    Watch {\n        /// The type URL of the resource.\n        type_url: &'static str,\n        /// The resource name (empty string for wildcard subscription).\n        name: String,\n        /// Unique identifier for this watcher.\n        watcher_id: WatcherId,\n        /// Channel to send resource events to the watcher.\n        event_tx: mpsc::Sender<ResourceEvent<DecodedResource>>,\n        /// Decoder function for this resource type.\n        decoder: DecoderFn,\n        /// Whether all resources must be present in SotW responses (per A53).\n        all_resources_required_in_sotw: bool,\n    },\n    /// Unsubscribe a watcher.\n    Unwatch {\n        /// The watcher to remove.\n        watcher_id: WatcherId,\n    },\n    /// Timer expired for a resource that was never received (gRFC A57).\n    ResourceTimerExpired {\n        /// The type URL of the resource.\n        type_url: String,\n        /// The resource name.\n        name: String,\n    },\n}\n\n/// Represents the subscription mode for a resource type.\n///\n/// This enum captures the mutually exclusive subscription states:\n/// - Wildcard: receive all resources of this type\n/// - Named: receive only specific resources by name\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum SubscriptionMode {\n    /// Wildcard subscription - receive all resources of this type.\n    /// In xDS protocol, this is represented by an empty resource_names list.\n    Wildcard,\n    /// Named subscription - receive only specific resources.\n    /// Contains the set of resource names to subscribe to.\n    Named(HashSet<String>),\n}\n\nimpl SubscriptionMode {\n    /// Get resource names for DiscoveryRequest.\n    /// Returns empty vec for wildcard (xDS spec: empty = all resources).\n    fn resource_names_for_request(&self) -> Vec<String> {\n        match self {\n            Self::Wildcard => Vec::new(),\n            Self::Named(names) => names.iter().cloned().collect(),\n        }\n    }\n}\n\n/// State of a cached resource per gRFC A88.\n#[derive(Debug, Clone)]\nenum ResourceState {\n    /// Resource has been requested but not yet received.\n    Requested,\n    /// Resource has been successfully received and validated.\n    Received,\n    /// Resource validation failed. Contains the error message.\n    NACKed(String),\n    /// Resource does not exist (server indicated deletion or absence).\n    DoesNotExist,\n}\n\n/// A cached resource entry.\n#[derive(Debug, Clone)]\nstruct CachedResource {\n    /// Current state of the resource.\n    state: ResourceState,\n    /// The decoded resource, if successfully received.\n    /// None if state is Requested, NACKed, or DoesNotExist.\n    resource: Option<Arc<DecodedResource>>,\n}\n\nimpl CachedResource {\n    /// Create a new cached resource in Requested state.\n    fn requested() -> Self {\n        Self {\n            state: ResourceState::Requested,\n            resource: None,\n        }\n    }\n\n    /// Create a cached resource in Received state.\n    fn received(resource: Arc<DecodedResource>) -> Self {\n        Self {\n            state: ResourceState::Received,\n            resource: Some(resource),\n        }\n    }\n\n    /// Create a cached resource in DoesNotExist state.\n    fn does_not_exist() -> Self {\n        Self {\n            state: ResourceState::DoesNotExist,\n            resource: None,\n        }\n    }\n\n    /// Create a cached resource in NACKed state.\n    fn nacked(error: String) -> Self {\n        Self {\n            state: ResourceState::NACKed(error),\n            resource: None,\n        }\n    }\n\n    /// Returns true if the resource is in Requested state (waiting for server response).\n    fn is_requested(&self) -> bool {\n        matches!(self.state, ResourceState::Requested)\n    }\n\n    /// Convert cached state to a ResourceEvent for notifying watchers.\n    /// Returns None if state is Requested (nothing to notify yet).\n    fn to_event(&self) -> Option<ResourceEvent<DecodedResource>> {\n        let (done, _rx) = ProcessingDone::channel();\n        match &self.state {\n            ResourceState::Received => {\n                self.resource\n                    .as_ref()\n                    .map(|r| ResourceEvent::ResourceChanged {\n                        result: Ok(Arc::clone(r)),\n                        done,\n                    })\n            }\n            ResourceState::DoesNotExist => Some(ResourceEvent::ResourceChanged {\n                result: Err(Error::ResourceDoesNotExist),\n                done,\n            }),\n            ResourceState::NACKed(error) => Some(ResourceEvent::ResourceChanged {\n                result: Err(Error::Validation(error.clone())),\n                done,\n            }),\n            ResourceState::Requested => None,\n        }\n    }\n}\n\n/// Per-type_url state tracking.\nstruct TypeState {\n    /// Decoder function for this resource type.\n    decoder: DecoderFn,\n    /// Version from last successful response.\n    version_info: String,\n    /// Nonce from last response (for ACK/NACK).\n    nonce: String,\n    /// Active watchers for this type.\n    watchers: HashMap<WatcherId, WatcherEntry>,\n    /// Current subscription mode (wildcard or named resources).\n    subscription: SubscriptionMode,\n    /// Resource cache: name -> cached resource.\n    cache: HashMap<String, CachedResource>,\n    /// Whether missing resources in SotW should be treated as deleted (per A53).\n    all_resources_required_in_sotw: bool,\n}\n\nimpl std::fmt::Debug for TypeState {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"TypeState\")\n            .field(\"decoder\", &\"<decoder fn>\")\n            .field(\"version_info\", &self.version_info)\n            .field(\"nonce\", &self.nonce)\n            .field(\"watchers\", &self.watchers)\n            .field(\"subscription\", &self.subscription)\n            .field(\"cache\", &format!(\"<{} entries>\", self.cache.len()))\n            .field(\n                \"all_resources_required_in_sotw\",\n                &self.all_resources_required_in_sotw,\n            )\n            .finish()\n    }\n}\n\nimpl TypeState {\n    fn new(decoder: DecoderFn, all_resources_required_in_sotw: bool) -> Self {\n        Self {\n            decoder,\n            version_info: String::new(),\n            nonce: String::new(),\n            watchers: HashMap::new(),\n            subscription: SubscriptionMode::Named(HashSet::new()),\n            cache: HashMap::new(),\n            all_resources_required_in_sotw,\n        }\n    }\n\n    /// Recalculate subscription mode from watchers.\n    fn recalculate_subscriptions(&mut self) {\n        let has_wildcard = self\n            .watchers\n            .values()\n            .any(|entry| entry.subscription.is_wildcard());\n\n        if has_wildcard {\n            self.subscription = SubscriptionMode::Wildcard;\n        } else {\n            let names: HashSet<String> = self\n                .watchers\n                .values()\n                .filter_map(|entry| match &entry.subscription {\n                    WatcherSubscription::Named(name) => Some(name.clone()),\n                    WatcherSubscription::Wildcard => None,\n                })\n                .collect();\n            self.subscription = SubscriptionMode::Named(names);\n        }\n    }\n\n    /// Get resource names to send in DiscoveryRequest.\n    fn resource_names_for_request(&self) -> Vec<String> {\n        self.subscription.resource_names_for_request()\n    }\n\n    /// Get senders for all watchers interested in a specific resource.\n    fn matching_watchers(&self, name: &str) -> Vec<mpsc::Sender<ResourceEvent<DecodedResource>>> {\n        self.watchers\n            .values()\n            .filter(|e| e.subscription.matches(name))\n            .map(|e| e.event_tx.clone())\n            .collect()\n    }\n}\n\n/// Specifies which resources a watcher is interested in.\n#[derive(Debug, Clone, PartialEq, Eq)]\nenum WatcherSubscription {\n    /// Wildcard subscription - receive all resources of this type.\n    Wildcard,\n    /// Named subscription - receive only the specified resource.\n    Named(String),\n}\n\nimpl WatcherSubscription {\n    /// Create a subscription from a resource name.\n    /// Empty string is treated as wildcard.\n    fn from_name(name: String) -> Self {\n        if name.is_empty() {\n            Self::Wildcard\n        } else {\n            Self::Named(name)\n        }\n    }\n\n    /// Check if this subscription matches a resource name.\n    fn matches(&self, resource_name: &str) -> bool {\n        match self {\n            Self::Wildcard => true,\n            Self::Named(name) => name == resource_name,\n        }\n    }\n\n    /// Returns true if this is a wildcard subscription.\n    fn is_wildcard(&self) -> bool {\n        matches!(self, Self::Wildcard)\n    }\n}\n\n/// Per-watcher state.\n#[derive(Debug)]\nstruct WatcherEntry {\n    /// Channel to send events to this watcher.\n    event_tx: mpsc::Sender<ResourceEvent<DecodedResource>>,\n    /// What resources this watcher is subscribed to.\n    subscription: WatcherSubscription,\n}\n\n/// The ADS worker manages the xDS stream and dispatches resources to watchers.\npub(crate) struct AdsWorker<TB, C, R> {\n    /// Transport builder for creating transports to xDS servers.\n    transport_builder: TB,\n    /// Codec for encoding/decoding messages.\n    codec: C,\n    /// Runtime for spawning tasks and sleeping.\n    runtime: R,\n    /// Node identification.\n    node: Node,\n    /// Backoff calculator for reconnection attempts.\n    backoff: Backoff,\n    /// Priority-ordered list of xDS servers.\n    /// Index 0 has the highest priority.\n    servers: Vec<ServerConfig>,\n    /// Timeout for initial resource response (gRFC A57). None = disabled.\n    resource_initial_timeout: Option<Duration>,\n    /// Sender for timer callback commands.\n    command_tx: mpsc::Sender<WorkerCommand>,\n    /// Receiver for commands from XdsClient.\n    command_rx: mpsc::Receiver<WorkerCommand>,\n    /// Per-type_url state.\n    type_states: HashMap<String, TypeState>,\n    /// Cancellation handles for resource timers (gRFC A57).\n    /// Key is (type_url, resource_name). Dropping the sender cancels the timer.\n    resource_timers: HashMap<(String, String), oneshot::Sender<()>>,\n}\n\nimpl<TB, C, R> AdsWorker<TB, C, R>\nwhere\n    TB: TransportBuilder,\n    C: XdsCodec,\n    R: Runtime,\n{\n    /// Create a new worker.\n    pub(crate) fn new(\n        transport_builder: TB,\n        codec: C,\n        runtime: R,\n        config: ClientConfig,\n        command_tx: mpsc::Sender<WorkerCommand>,\n        command_rx: mpsc::Receiver<WorkerCommand>,\n    ) -> Self {\n        Self {\n            transport_builder,\n            codec,\n            runtime,\n            node: config.node,\n            backoff: Backoff::new(config.retry_policy),\n            servers: config.servers,\n            resource_initial_timeout: config.resource_initial_timeout,\n            command_tx,\n            command_rx,\n            type_states: HashMap::new(),\n            resource_timers: HashMap::new(),\n        }\n    }\n\n    /// Run the worker event loop.\n    ///\n    /// This method runs until all `XdsClient` handles are dropped\n    /// (which closes the command channel).\n    pub(crate) async fn run(mut self) {\n        loop {\n            // Wait for at least one subscription before connecting.\n            // This prevents deadlock with servers that require a message before\n            // sending response headers - we need something to send.\n            while self.type_states.is_empty() {\n                match self.command_rx.recv().await {\n                    Some(cmd) => {\n                        let _ = self\n                            .handle_command::<<TB::Transport as Transport>::Stream>(None, cmd)\n                            .await;\n                    }\n                    None => return,\n                }\n            }\n\n            // Nonces are tied to the stream\n            for type_state in self.type_states.values_mut() {\n                type_state.nonce.clear();\n            }\n\n            // Connect to server.\n            // Future extension (gRFC A71): Try servers in priority order with fallback.\n            let server = match self.servers.first() {\n                Some(s) => s,\n                None => return, // No servers configured\n            };\n\n            let transport = match self.transport_builder.build(server).await {\n                Ok(t) => t,\n                Err(_) => {\n                    match self.backoff.next_backoff() {\n                        Some(backoff) => self.runtime.sleep(backoff).await,\n                        None => return, // Max attempts exceeded\n                    }\n                    continue;\n                }\n            };\n\n            let stream = match transport.new_stream(self.build_initial_requests()).await {\n                Ok(s) => {\n                    self.backoff.reset();\n                    s\n                }\n                Err(_) => {\n                    match self.backoff.next_backoff() {\n                        Some(backoff) => self.runtime.sleep(backoff).await,\n                        None => return, // Max attempts exceeded\n                    }\n                    continue;\n                }\n            };\n\n            match self.run_connected(stream).await {\n                Ok(()) => return, // shutdown\n                Err(_e) => {\n                    match self.backoff.next_backoff() {\n                        Some(backoff) => self.runtime.sleep(backoff).await,\n                        None => return, // Max attempts exceeded\n                    }\n                    continue;\n                }\n            }\n        }\n    }\n\n    /// Build initial DiscoveryRequests for all active subscriptions.\n    ///\n    /// These are sent when establishing the stream to prevent deadlock with\n    /// servers that don't send response headers until they receive a request.\n    fn build_initial_requests(&self) -> Vec<Bytes> {\n        let mut requests = Vec::new();\n\n        for (type_url, type_state) in &self.type_states {\n            if type_state.watchers.is_empty() {\n                continue;\n            }\n\n            let resource_names = type_state.resource_names_for_request();\n\n            let request = DiscoveryRequest {\n                node: &self.node,\n                type_url,\n                resource_names: &resource_names,\n                version_info: &type_state.version_info,\n                response_nonce: \"\", // Initial request has empty nonce\n                error_detail: None,\n            };\n\n            if let Ok(bytes) = self.codec.encode_request(&request) {\n                requests.push(bytes);\n            }\n        }\n\n        requests\n    }\n\n    /// Run the main event loop while connected.\n    ///\n    /// Returns `Ok(())` if the worker should shut down (command channel closed).\n    /// Returns `Err` if an error occurred and the worker should reconnect.\n    async fn run_connected<S: TransportStream>(&mut self, mut stream: S) -> Result<()> {\n        loop {\n            tokio::select! {\n                result = stream.recv() => {\n                    match result {\n                        Ok(Some(bytes)) => {\n                            self.handle_response(&mut stream, bytes).await?;\n                        }\n                        // Stream closed by server; return Err to trigger reconnection\n                        Ok(None) => return Err(Error::StreamClosed),\n                        Err(e) => return Err(e),\n                    }\n                }\n\n                cmd = self.command_rx.recv() => {\n                    match cmd {\n                        Some(cmd) => {\n                            self.handle_command(Some(&mut stream), cmd).await?;\n                        }\n                        None => return Ok(()),\n                    }\n                }\n            }\n        }\n    }\n\n    /// Handle a command, optionally sending network requests if connected.\n    ///\n    /// When `stream` is `None`, only state updates are performed (disconnected mode).\n    /// When `stream` is `Some`, subscription changes trigger network requests.\n    async fn handle_command<S: TransportStream>(\n        &mut self,\n        stream: Option<&mut S>,\n        cmd: WorkerCommand,\n    ) -> Result<()> {\n        match cmd {\n            WorkerCommand::Watch {\n                type_url,\n                name,\n                watcher_id,\n                event_tx,\n                decoder,\n                all_resources_required_in_sotw,\n            } => {\n                if self.add_watcher(\n                    type_url,\n                    name,\n                    watcher_id,\n                    event_tx,\n                    decoder,\n                    all_resources_required_in_sotw,\n                ) && let Some(stream) = stream\n                {\n                    self.send_request(stream, type_url).await?;\n                }\n            }\n            WorkerCommand::Unwatch { watcher_id } => {\n                if let Some((type_url, true)) = self.remove_watcher(watcher_id)\n                    && let Some(stream) = stream\n                {\n                    self.send_request(stream, &type_url).await?;\n                }\n            }\n            WorkerCommand::ResourceTimerExpired { type_url, name } => {\n                self.handle_resource_timeout(&type_url, &name).await;\n            }\n        }\n        Ok(())\n    }\n\n    /// Add a watcher to the state.\n    ///\n    /// If the resource is already cached, the watcher receives the cached state immediately.\n    /// Returns true if subscriptions changed (need to send new request to server).\n    fn add_watcher(\n        &mut self,\n        type_url: &'static str,\n        name: String,\n        watcher_id: WatcherId,\n        event_tx: mpsc::Sender<ResourceEvent<DecodedResource>>,\n        decoder: DecoderFn,\n        all_resources_required_in_sotw: bool,\n    ) -> bool {\n        let type_url_string = type_url.to_string();\n        let type_state = self\n            .type_states\n            .entry(type_url_string.clone())\n            .or_insert_with(|| TypeState::new(decoder, all_resources_required_in_sotw));\n\n        let old_subscription = type_state.subscription.clone();\n        let watcher_subscription = WatcherSubscription::from_name(name.clone());\n\n        // Track if we need to start a timer (resource in Requested state)\n        let mut start_timer_for: Option<String> = None;\n\n        // For named subscriptions, check cache and send cached state to new watcher.\n        // For wildcard subscriptions, watchers receive updates as they come in.\n        if let WatcherSubscription::Named(ref resource_name) = watcher_subscription {\n            let cached = type_state\n                .cache\n                .entry(resource_name.clone())\n                .or_insert_with(CachedResource::requested);\n\n            if let Some(event) = cached.to_event() {\n                // Send cached state to watcher (non-blocking, ignore if full)\n                let _ = event_tx.try_send(event);\n            }\n\n            if cached.is_requested() {\n                // Resource pending - start a timer (gRFC A57)\n                start_timer_for = Some(resource_name.clone());\n            }\n        }\n\n        type_state.watchers.insert(\n            watcher_id,\n            WatcherEntry {\n                event_tx,\n                subscription: watcher_subscription,\n            },\n        );\n        type_state.recalculate_subscriptions();\n\n        let subscriptions_changed = type_state.subscription != old_subscription;\n\n        // Start timer if resource is in Requested state\n        if let (Some(resource_name), Some(timeout)) =\n            (start_timer_for, self.resource_initial_timeout)\n        {\n            self.start_resource_timer(&type_url_string, resource_name, timeout);\n        }\n\n        subscriptions_changed\n    }\n\n    /// Remove a watcher from the state.\n    /// Returns the type_url and whether subscriptions changed.\n    fn remove_watcher(&mut self, watcher_id: WatcherId) -> Option<(String, bool)> {\n        let type_url = self\n            .type_states\n            .iter()\n            .find(|(_, state)| state.watchers.contains_key(&watcher_id))\n            .map(|(url, _)| url.clone())?;\n\n        let type_state = self.type_states.get_mut(&type_url)?;\n\n        let old_subscription = type_state.subscription.clone();\n\n        type_state.watchers.remove(&watcher_id);\n        type_state.recalculate_subscriptions();\n\n        let subscriptions_changed = type_state.subscription != old_subscription;\n\n        if type_state.watchers.is_empty() {\n            self.type_states.remove(&type_url);\n            // Cancel all pending resource timers for this type.\n            self.resource_timers.retain(|key, _| key.0 != type_url);\n        }\n\n        Some((type_url, subscriptions_changed))\n    }\n\n    /// Send a DiscoveryRequest for a type.\n    async fn send_request<S: TransportStream>(&self, stream: &mut S, type_url: &str) -> Result<()> {\n        let type_state = match self.type_states.get(type_url) {\n            Some(s) => s,\n            None => return Ok(()),\n        };\n\n        let resource_names = type_state.resource_names_for_request();\n        let request = DiscoveryRequest {\n            node: &self.node,\n            type_url,\n            resource_names: &resource_names,\n            version_info: &type_state.version_info,\n            response_nonce: &type_state.nonce,\n            error_detail: None,\n        };\n\n        let bytes = self.codec.encode_request(&request)?;\n        stream.send(bytes).await\n    }\n\n    /// Handle a response from the server.\n    ///\n    /// Implements partial success per gRFC A46: valid resources are accepted even\n    /// if some resources in the response fail validation. Each resource is processed\n    /// independently:\n    /// - Valid resources are cached and dispatched to watchers\n    /// - Invalid resources are cached as NACKed and errors sent to specific watchers\n    /// - Missing resources (for types with ALL_RESOURCES_REQUIRED_IN_SOTW) are marked deleted\n    async fn handle_response<S: TransportStream>(\n        &mut self,\n        stream: &mut S,\n        bytes: Bytes,\n    ) -> Result<()> {\n        let response = self.codec.decode_response(bytes)?;\n        let type_url = response.type_url.clone();\n\n        let decoder = match self.type_states.get(&type_url) {\n            Some(s) => &s.decoder,\n            None => {\n                return Ok(());\n            }\n        };\n\n        // Decode all resources, tracking valid and invalid separately.\n        // Per A46, we accept valid resources even if some fail validation.\n        // Per A88, we categorize errors:\n        // - top_level_errors: deserialization failures where name cannot be extracted\n        // - per_resource_errors: validation failures where name is known\n        let mut valid_resources: Vec<DecodedResource> = Vec::new();\n        let mut top_level_errors: Vec<String> = Vec::new();\n        let mut per_resource_errors: Vec<(String, String)> = Vec::new(); // (name, error)\n\n        for resource_any in &response.resources {\n            match decoder(resource_any.value.clone()) {\n                crate::resource::DecodeResult::Success { resource, .. } => {\n                    valid_resources.push(resource);\n                }\n                crate::resource::DecodeResult::ResourceError { name, error } => {\n                    per_resource_errors.push((name, error.to_string()));\n                }\n                crate::resource::DecodeResult::TopLevelError(error) => {\n                    top_level_errors.push(error.to_string());\n                }\n            }\n        }\n\n        if let Some(type_state) = self.type_states.get_mut(&type_url) {\n            type_state.nonce = response.nonce.clone();\n        }\n\n        let received_names: HashSet<String> = valid_resources\n            .iter()\n            .map(|r| r.name().to_string())\n            .collect();\n\n        let mut processing_done_futures = self.dispatch_resources(&type_url, valid_resources).await;\n\n        // Only notify watchers for per-resource errors (where we know the name).\n        // Top-level errors have no associated name, so no watcher to notify.\n        for (resource_name, error) in &per_resource_errors {\n            self.notify_resource_error(&type_url, resource_name, error)\n                .await;\n        }\n\n        // Detect deleted resources (per A53):\n        // For resource types with ALL_RESOURCES_REQUIRED_IN_SOTW = true,\n        // any previously-received resource not in this response is deleted.\n        let deleted_futures = self\n            .detect_deleted_resources(&type_url, &received_names)\n            .await;\n        processing_done_futures.extend(deleted_futures);\n\n        // Wait for all watchers to finish processing.\n        for rx in processing_done_futures {\n            let _ = rx.await;\n        }\n\n        let has_errors = !top_level_errors.is_empty() || !per_resource_errors.is_empty();\n        if !has_errors {\n            // Only update version on ACK; NACK must keep the old version so the\n            // server knows which version the client is still running.\n            if let Some(ts) = self.type_states.get_mut(&type_url) {\n                ts.version_info = response.version_info.clone();\n            }\n            self.send_ack(stream, &response).await\n        } else {\n            // Build NACK message combining both error categories\n            let mut error_parts = Vec::new();\n\n            if !top_level_errors.is_empty() {\n                error_parts.push(format!(\"top level errors: {}\", top_level_errors.join(\"; \")));\n            }\n\n            if !per_resource_errors.is_empty() {\n                let per_resource_msg = per_resource_errors\n                    .iter()\n                    .map(|(name, err)| format!(\"{name}: {err}\"))\n                    .collect::<Vec<_>>()\n                    .join(\"; \");\n                error_parts.push(per_resource_msg);\n            }\n\n            self.send_nack(stream, &response, error_parts.join(\"; \"))\n                .await\n        }\n    }\n\n    /// Dispatch decoded resources to watchers and update cache.\n    ///\n    /// Returns futures that resolve when watchers signal ProcessingDone.\n    /// Uses backpressure: waits if a watcher's channel is full.\n    async fn dispatch_resources(\n        &mut self,\n        type_url: &str,\n        resources: Vec<DecodedResource>,\n    ) -> Vec<oneshot::Receiver<()>> {\n        let mut processing_done_futures = Vec::new();\n\n        let watcher_info: Vec<_> = match self.type_states.get_mut(type_url) {\n            Some(s) => {\n                for resource in &resources {\n                    let resource_name = resource.name().to_string();\n                    s.cache.insert(\n                        resource_name,\n                        CachedResource::received(Arc::new(resource.clone())),\n                    );\n                }\n                s.watchers\n                    .iter()\n                    .map(|(id, entry)| (*id, entry.event_tx.clone(), entry.subscription.clone()))\n                    .collect()\n            }\n            None => return processing_done_futures,\n        };\n\n        // Cancel resource timers for received resources (gRFC A57).\n        for resource in &resources {\n            self.resource_timers\n                .remove(&(type_url.to_string(), resource.name().to_string()));\n        }\n\n        for resource in resources {\n            let resource_name = resource.name().to_string();\n            let resource = Arc::new(resource);\n\n            for (_watcher_id, event_tx, subscription) in watcher_info.clone() {\n                if subscription.matches(&resource_name) {\n                    let (done, rx) = ProcessingDone::channel();\n                    let event = ResourceEvent::ResourceChanged {\n                        result: Ok(Arc::clone(&resource)),\n                        done,\n                    };\n                    // Use backpressure: await if channel is full.\n                    // Ignore send errors (watcher dropped).\n                    let _ = event_tx.send(event).await;\n                    processing_done_futures.push(rx);\n                }\n            }\n        }\n\n        processing_done_futures\n    }\n\n    /// Notify watchers of a validation error for a specific resource.\n    ///\n    /// Per gRFC A46/A88, errors are routed only to watchers interested in\n    /// that specific resource (plus wildcard watchers).\n    async fn notify_resource_error(&mut self, type_url: &str, resource_name: &str, error: &str) {\n        let type_state = match self.type_states.get_mut(type_url) {\n            Some(s) => s,\n            None => return,\n        };\n\n        type_state.cache.insert(\n            resource_name.to_string(),\n            CachedResource::nacked(error.to_string()),\n        );\n\n        // Cancel the resource timer (gRFC A57).\n        self.resource_timers\n            .remove(&(type_url.to_string(), resource_name.to_string()));\n\n        for event_tx in type_state.matching_watchers(resource_name) {\n            let (done, _rx) = ProcessingDone::channel();\n            let event = ResourceEvent::ResourceChanged {\n                result: Err(Error::Validation(error.to_string())),\n                done,\n            };\n            let _ = event_tx.send(event).await;\n        }\n    }\n\n    /// Detect resources that were deleted (present in cache but not in response).\n    ///\n    /// Per gRFC A53, for resource types with ALL_RESOURCES_REQUIRED_IN_SOTW = true,\n    /// if a previously-received resource is absent from a new SotW response,\n    /// it is treated as deleted.\n    async fn detect_deleted_resources(\n        &mut self,\n        type_url: &str,\n        received_names: &HashSet<String>,\n    ) -> Vec<oneshot::Receiver<()>> {\n        let mut processing_done_futures = Vec::new();\n\n        let type_state = match self.type_states.get_mut(type_url) {\n            Some(s) => s,\n            None => return processing_done_futures,\n        };\n\n        if !type_state.all_resources_required_in_sotw {\n            return processing_done_futures;\n        }\n\n        let deleted_names: Vec<String> = type_state\n            .cache\n            .iter()\n            .filter(|(name, cached)| {\n                matches!(cached.state, ResourceState::Received) && !received_names.contains(*name)\n            })\n            .map(|(name, _)| name.clone())\n            .collect();\n\n        for name in deleted_names {\n            type_state\n                .cache\n                .insert(name.clone(), CachedResource::does_not_exist());\n\n            for event_tx in type_state.matching_watchers(&name) {\n                let (done, rx) = ProcessingDone::channel();\n                let event = ResourceEvent::ResourceChanged {\n                    result: Err(Error::ResourceDoesNotExist),\n                    done,\n                };\n                let _ = event_tx.send(event).await;\n                processing_done_futures.push(rx);\n            }\n        }\n\n        processing_done_futures\n    }\n\n    /// Send an ACK for a response.\n    async fn send_ack<S: TransportStream>(\n        &self,\n        stream: &mut S,\n        response: &DiscoveryResponse,\n    ) -> Result<()> {\n        let type_state = match self.type_states.get(&response.type_url) {\n            Some(s) => s,\n            None => return Ok(()),\n        };\n\n        let resource_names = type_state.resource_names_for_request();\n        let request = DiscoveryRequest {\n            node: &self.node,\n            type_url: &response.type_url,\n            resource_names: &resource_names,\n            version_info: &response.version_info,\n            response_nonce: &response.nonce,\n            error_detail: None,\n        };\n\n        let bytes = self.codec.encode_request(&request)?;\n        stream.send(bytes).await\n    }\n\n    /// Send a NACK for a response.\n    async fn send_nack<S: TransportStream>(\n        &self,\n        stream: &mut S,\n        response: &DiscoveryResponse,\n        error_message: String,\n    ) -> Result<()> {\n        let type_state = match self.type_states.get(&response.type_url) {\n            Some(s) => s,\n            None => return Ok(()),\n        };\n\n        let resource_names = type_state.resource_names_for_request();\n        let request = DiscoveryRequest {\n            node: &self.node,\n            type_url: &response.type_url,\n            resource_names: &resource_names,\n            version_info: &type_state.version_info, // Keep old version for NACK\n            response_nonce: &response.nonce,\n            error_detail: Some(ErrorDetail {\n                code: 3, // INVALID_ARGUMENT\n                message: error_message,\n            }),\n        };\n\n        let bytes = self.codec.encode_request(&request)?;\n        stream.send(bytes).await\n    }\n\n    /// Start a timer for a resource in Requested state (gRFC A57).\n    ///\n    /// If a timer is already running for this resource, this is a no-op to\n    /// preserve the original timeout deadline per A57.\n    ///\n    /// When the timer fires, it sends a `ResourceTimerExpired` command.\n    /// The handler checks if the resource is still in Requested state before acting.\n    fn start_resource_timer(&mut self, type_url: &str, name: String, timeout: Duration) {\n        let key = (type_url.to_string(), name.clone());\n\n        // Don't reset an existing timer — A57 says timeout starts on first request.\n        if self.resource_timers.contains_key(&key) {\n            return;\n        }\n\n        let (cancel_tx, cancel_rx) = oneshot::channel::<()>();\n        let type_url_owned = type_url.to_string();\n        let command_tx = self.command_tx.clone();\n        let runtime = self.runtime.clone();\n\n        self.runtime.spawn(async move {\n            tokio::select! {\n                _ = runtime.sleep(timeout) => {\n                    let _ = command_tx.send(WorkerCommand::ResourceTimerExpired {\n                        type_url: type_url_owned,\n                        name,\n                    }).await;\n                }\n                _ = cancel_rx => {}\n            }\n        });\n\n        self.resource_timers.insert(key, cancel_tx);\n    }\n\n    /// Handle a resource timer expiration (gRFC A57).\n    ///\n    /// If the resource is still in Requested state, marks it as DoesNotExist\n    /// and notifies all watchers interested in this resource.\n    async fn handle_resource_timeout(&mut self, type_url: &str, name: &str) {\n        self.resource_timers\n            .remove(&(type_url.to_string(), name.to_string()));\n\n        let type_state = match self.type_states.get_mut(type_url) {\n            Some(s) => s,\n            None => return,\n        };\n\n        let is_pending = type_state\n            .cache\n            .get(name)\n            .map(|c| c.is_requested())\n            .unwrap_or(true);\n\n        if !is_pending {\n            return;\n        }\n\n        type_state\n            .cache\n            .insert(name.to_string(), CachedResource::does_not_exist());\n\n        for event_tx in type_state.matching_watchers(name) {\n            let (done, _rx) = ProcessingDone::channel();\n            let event = ResourceEvent::ResourceChanged {\n                result: Err(Error::ResourceDoesNotExist),\n                done,\n            };\n            let _ = event_tx.send(event).await;\n        }\n    }\n}\n"
  },
  {
    "path": "xds-client/src/codec/mod.rs",
    "content": "//! Codec for encoding/decoding xDS messages.\n//!\n//! The codec layer converts between crate-owned message types\n//! ([`DiscoveryRequest`], [`DiscoveryResponse`]) and serialized bytes.\n//! This abstraction allows different protobuf implementations\n//! (prost, google-protobuf) to be used with the same xDS client logic.\n\nuse crate::error::Result;\nuse crate::message::{DiscoveryRequest, DiscoveryResponse};\nuse bytes::Bytes;\n\n#[cfg(feature = \"codegen-prost\")]\npub mod prost;\n\n/// Trait for encoding/decoding xDS discovery messages.\n///\n/// Implementations convert between the crate-owned message types\n/// and their serialized wire format.\npub trait XdsCodec: Send + Sync + 'static {\n    /// Encode a [`DiscoveryRequest`] to bytes.\n    fn encode_request(&self, request: &DiscoveryRequest<'_>) -> Result<Bytes>;\n\n    /// Decode bytes into a [`DiscoveryResponse`].\n    fn decode_response(&self, bytes: Bytes) -> Result<DiscoveryResponse>;\n}\n"
  },
  {
    "path": "xds-client/src/codec/prost.rs",
    "content": "//! Prost-based codec using envoy-types.\n\nuse crate::codec::XdsCodec;\nuse crate::error::{Error, Result};\nuse crate::message::{DiscoveryRequest, DiscoveryResponse, ResourceAny};\nuse bytes::Bytes;\nuse prost::Message;\n\n/// A codec that uses prost/envoy-types for serialization.\n#[derive(Debug, Clone, Copy, Default)]\npub struct ProstCodec;\n\nimpl XdsCodec for ProstCodec {\n    fn encode_request(&self, request: &DiscoveryRequest<'_>) -> Result<Bytes> {\n        use envoy_types::pb::envoy::config::core::v3 as core;\n        use envoy_types::pb::envoy::service::discovery::v3 as discovery;\n        use envoy_types::pb::google::rpc::Status;\n\n        let proto_request = discovery::DiscoveryRequest {\n            version_info: request.version_info.to_owned(),\n            node: Some(core::Node {\n                id: request.node.id.clone().unwrap_or_default(),\n                cluster: request.node.cluster.clone().unwrap_or_default(),\n                user_agent_name: request.node.user_agent_name.clone(),\n                user_agent_version_type: Some(core::node::UserAgentVersionType::UserAgentVersion(\n                    request.node.user_agent_version.clone(),\n                )),\n                locality: request.node.locality.as_ref().map(|l| core::Locality {\n                    region: l.region.clone(),\n                    zone: l.zone.clone(),\n                    sub_zone: l.sub_zone.clone(),\n                }),\n                ..Default::default()\n            }),\n            resource_names: request.resource_names.to_vec(),\n            type_url: request.type_url.to_owned(),\n            response_nonce: request.response_nonce.to_owned(),\n            error_detail: request.error_detail.as_ref().map(|e| Status {\n                code: e.code,\n                message: e.message.clone(),\n                details: vec![],\n            }),\n            ..Default::default()\n        };\n\n        Ok(proto_request.encode_to_vec().into())\n    }\n\n    fn decode_response(&self, bytes: Bytes) -> Result<DiscoveryResponse> {\n        use envoy_types::pb::envoy::service::discovery::v3 as discovery;\n\n        let proto_response = discovery::DiscoveryResponse::decode(bytes).map_err(Error::Decode)?;\n\n        Ok(DiscoveryResponse {\n            version_info: proto_response.version_info,\n            resources: proto_response\n                .resources\n                .into_iter()\n                .map(|any| ResourceAny {\n                    type_url: any.type_url,\n                    value: any.value.into(),\n                })\n                .collect(),\n            type_url: proto_response.type_url,\n            nonce: proto_response.nonce,\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::message::{ErrorDetail, Locality, Node};\n\n    #[test]\n    fn test_encode_request_minimal() {\n        let codec = ProstCodec;\n        let node = Node::new(\"grpc\", \"1.0\");\n        let resource_names = vec![\"listener-1\".to_string()];\n        let request = DiscoveryRequest {\n            version_info: \"\",\n            node: &node,\n            type_url: \"type.googleapis.com/envoy.config.listener.v3.Listener\",\n            resource_names: &resource_names,\n            response_nonce: \"\",\n            error_detail: None,\n        };\n\n        let bytes = codec.encode_request(&request).unwrap();\n        assert!(!bytes.is_empty());\n\n        // Verify we can decode it back with prost\n        use envoy_types::pb::envoy::service::discovery::v3 as discovery;\n        let decoded = discovery::DiscoveryRequest::decode(bytes).unwrap();\n        assert_eq!(decoded.type_url, request.type_url);\n        assert_eq!(decoded.resource_names, request.resource_names);\n    }\n\n    #[test]\n    fn test_encode_request_with_node() {\n        let codec = ProstCodec;\n        let node = Node::new(\"grpc\", \"1.0\")\n            .with_id(\"node-1\")\n            .with_cluster(\"cluster-1\")\n            .with_locality(Locality {\n                region: \"us-west\".to_string(),\n                zone: \"us-west-1a\".to_string(),\n                sub_zone: \"rack-1\".to_string(),\n            });\n        let resource_names: Vec<String> = Vec::new();\n        let request = DiscoveryRequest {\n            version_info: \"\",\n            node: &node,\n            type_url: \"type.googleapis.com/envoy.config.cluster.v3.Cluster\",\n            resource_names: &resource_names,\n            response_nonce: \"\",\n            error_detail: None,\n        };\n\n        let bytes = codec.encode_request(&request).unwrap();\n\n        use envoy_types::pb::envoy::config::core::v3 as core;\n        use envoy_types::pb::envoy::service::discovery::v3 as discovery;\n        let decoded = discovery::DiscoveryRequest::decode(bytes).unwrap();\n        let node = decoded.node.unwrap();\n        assert_eq!(node.id, \"node-1\");\n        assert_eq!(node.cluster, \"cluster-1\");\n        assert_eq!(node.user_agent_name, \"grpc\");\n        // Verify user_agent_version is properly encoded\n        match node.user_agent_version_type {\n            Some(core::node::UserAgentVersionType::UserAgentVersion(version)) => {\n                assert_eq!(version, \"1.0\");\n            }\n            _ => panic!(\"Expected UserAgentVersion to be set\"),\n        }\n        let locality = node.locality.unwrap();\n        assert_eq!(locality.region, \"us-west\");\n        assert_eq!(locality.zone, \"us-west-1a\");\n        assert_eq!(locality.sub_zone, \"rack-1\");\n    }\n\n    #[test]\n    fn test_decode_response() {\n        use envoy_types::pb::envoy::service::discovery::v3 as discovery;\n        use envoy_types::pb::google::protobuf::Any;\n\n        let proto_response = discovery::DiscoveryResponse {\n            version_info: \"1\".to_string(),\n            type_url: \"type.googleapis.com/envoy.config.listener.v3.Listener\".to_string(),\n            nonce: \"nonce-1\".to_string(),\n            resources: vec![Any {\n                type_url: \"type.googleapis.com/envoy.config.listener.v3.Listener\".to_string(),\n                value: b\"fake-listener-bytes\".to_vec(),\n            }],\n            ..Default::default()\n        };\n\n        let bytes: Bytes = proto_response.encode_to_vec().into();\n\n        let codec = ProstCodec;\n        let response = codec.decode_response(bytes).unwrap();\n\n        assert_eq!(response.version_info, \"1\");\n        assert_eq!(\n            response.type_url,\n            \"type.googleapis.com/envoy.config.listener.v3.Listener\"\n        );\n        assert_eq!(response.nonce, \"nonce-1\");\n        assert_eq!(response.resources.len(), 1);\n        assert_eq!(\n            response.resources[0].type_url,\n            \"type.googleapis.com/envoy.config.listener.v3.Listener\"\n        );\n        assert_eq!(response.resources[0].value.as_ref(), b\"fake-listener-bytes\");\n    }\n\n    #[test]\n    fn test_roundtrip() {\n        use envoy_types::pb::envoy::service::discovery::v3 as discovery;\n\n        let codec = ProstCodec;\n\n        let node = Node::new(\"grpc\", \"1.0\");\n        let resource_names = vec![\"res-1\".to_string(), \"res-2\".to_string()];\n        let request = DiscoveryRequest {\n            version_info: \"42\",\n            node: &node,\n            type_url: \"type.googleapis.com/test.Resource\",\n            resource_names: &resource_names,\n            response_nonce: \"nonce-abc\",\n            error_detail: Some(ErrorDetail {\n                code: 3, // INVALID_ARGUMENT\n                message: \"validation failed\".to_string(),\n            }),\n        };\n\n        let request_bytes = codec.encode_request(&request).unwrap();\n\n        let proto_request = discovery::DiscoveryRequest::decode(request_bytes).unwrap();\n        assert_eq!(proto_request.version_info, \"42\");\n        assert_eq!(proto_request.response_nonce, \"nonce-abc\");\n        let error = proto_request.error_detail.unwrap();\n        assert_eq!(error.code, 3);\n        assert_eq!(error.message, \"validation failed\");\n    }\n}\n"
  },
  {
    "path": "xds-client/src/error.rs",
    "content": "//! Error types for the xDS client.\n\nuse thiserror::Error;\n\n/// Error type for the xDS client.\n#[derive(Debug, Error)]\npub enum Error {\n    /// Failed to connect to the xDS server.\n    #[error(\"failed to connect: {0}\")]\n    Connection(String),\n\n    /// Error on the ADS stream.\n    #[cfg(feature = \"transport-tonic\")]\n    #[error(\"stream error: {0}\")]\n    Stream(#[from] tonic::Status),\n\n    /// The stream was closed unexpectedly.\n    #[error(\"stream closed unexpectedly\")]\n    StreamClosed,\n\n    /// Failed to decode a protobuf message.\n    #[cfg(feature = \"codegen-prost\")]\n    #[error(\"decode error: {0}\")]\n    Decode(#[from] prost::DecodeError),\n\n    /// Resource validation failed.\n    #[error(\"resource validation failed: {0}\")]\n    Validation(String),\n\n    /// Resource does not exist.\n    ///\n    /// This indicates the resource has been deleted or was never created.\n    #[error(\"resource does not exist\")]\n    ResourceDoesNotExist,\n}\n\n/// Result type alias for xDS client operations.\npub type Result<T> = std::result::Result<T, Error>;\n"
  },
  {
    "path": "xds-client/src/lib.rs",
    "content": "//! A Rust implementation of [xDS](https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol) client.\n//!\n//! This crate provides a protocol-agnostic xDS client. It handles:\n//! - ADS stream management (connection, reconnection, etc.)\n//! - Resource subscription and watching\n//! - Version/nonce tracking and ACK/NACK\n//!\n//! It does NOT contain gRPC-specific logic such as:\n//! - LDS -> RDS -> CDS -> EDS cascading\n//! - gRPC-specific resource validation\n//! - Service config generation\n//!\n//! Instead a gRPC library can use this crate to build these features.\n//!\n//! # Example\n//!\n//! ```ignore\n//! use xds_client::{XdsClient, ClientConfig, Node, ResourceEvent};\n//!\n//! // Create node and configuration\n//! let node = Node::new(\"grpc\", \"1.0\").with_id(\"my-node\");\n//! let config = ClientConfig::new(node, \"https://xds.example.com:443\");\n//!\n//! // Build client with transport, codec, and runtime\n//! let client = XdsClient::builder(config, transport, codec, runtime).build();\n//!\n//! // Watch for Listener resources\n//! let mut watcher = client.watch::<Listener>(\"my-listener\").await;\n//! while let Some(event) = watcher.next().await {\n//!     match event {\n//!         ResourceEvent::ResourceChanged { result: Ok(resource), done } => {\n//!             // Process the resource, possibly add cascading watches.\n//!             client.watch::<RouteConfiguration>(&resource.route_name()).await;\n//!             // Signal is sent automatically when done is dropped\n//!         }\n//!         ResourceEvent::ResourceChanged { result: Err(error), .. } => {\n//!             // Resource was invalidated (validation error or deleted)\n//!             eprintln!(\"Resource invalidated: {}\", error);\n//!         }\n//!         ResourceEvent::AmbientError { error, .. } => {\n//!             // Non-fatal error, continue using cached resource\n//!             eprintln!(\"Ambient error: {}\", error);\n//!         }\n//!     }\n//! }\n//! ```\n//!\n//! # Feature Flags\n//!\n//! - `transport-tonic`: Enables the use of the `tonic` transport. This enables `rt-tokio` and `codegen-prost` features. Enabled by default.\n//! - `rt-tokio`: Enables the use of the `tokio` runtime. Enabled by default.\n//! - `codegen-prost`: Enables the use of the `prost` codec generated resources. Enabled by default.\n\npub mod client;\npub mod codec;\npub mod error;\npub mod message;\npub mod resource;\npub mod runtime;\npub mod transport;\n\npub use client::config::{ClientConfig, ServerConfig};\npub use client::retry::{Backoff, RetryPolicy};\npub use client::watch::{ProcessingDone, ResourceEvent, ResourceWatcher};\npub use client::{XdsClient, XdsClientBuilder};\npub use codec::XdsCodec;\npub use error::{Error, Result};\npub use message::{DiscoveryRequest, DiscoveryResponse, ErrorDetail, Locality, Node, ResourceAny};\npub use resource::{DecodeResult, DecodedResource, Resource};\npub use runtime::Runtime;\npub use transport::{Transport, TransportBuilder, TransportStream};\n\n// Tokio runtime\n#[cfg(feature = \"rt-tokio\")]\npub use runtime::tokio::TokioRuntime;\n\n// Tonic transport\n#[cfg(feature = \"transport-tonic\")]\npub use transport::tonic::{TonicTransport, TonicTransportBuilder};\n\n// Prost codec\n#[cfg(feature = \"codegen-prost\")]\npub use codec::prost::ProstCodec;\n"
  },
  {
    "path": "xds-client/src/message.rs",
    "content": "//! Crate-owned xDS message types.\n//!\n//! These types are codegen-agnostic and serve as the interface between\n//! the xDS client logic and the codec layer. The codec converts these\n//! to/from the wire format (e.g., prost/envoy-types or google-protobuf).\n\nuse bytes::Bytes;\n\n/// A discovery request to send to the xDS server.\n///\n/// This struct borrows data to avoid unnecessary allocations when encoding.\n/// The data only needs to live long enough for the codec to encode it.\n#[derive(Debug, Clone)]\npub struct DiscoveryRequest<'a> {\n    /// The version_info provided in the most recent successfully processed\n    /// response for this type, or empty for the first request.\n    pub version_info: &'a str,\n    /// The node making the request.\n    pub node: &'a Node,\n    /// List of resource names to subscribe to.\n    pub resource_names: &'a [String],\n    /// Type URL of the resource being requested.\n    pub type_url: &'a str,\n    /// The nonce from the most recent successfully processed response,\n    /// or empty for the first request.\n    pub response_nonce: &'a str,\n    /// Error details if this is a NACK (negative acknowledgment).\n    pub error_detail: Option<ErrorDetail>,\n}\n\n/// A discovery response from the xDS server.\n#[derive(Debug, Clone, Default)]\npub struct DiscoveryResponse {\n    /// The version of the response data.\n    pub version_info: String,\n    /// The response resources wrapped as Any protos.\n    pub resources: Vec<ResourceAny>,\n    /// Type URL of the resources.\n    pub type_url: String,\n    /// Nonce for this response, to be echoed back in the next request.\n    pub nonce: String,\n}\n\n/// A resource wrapped as google.protobuf.Any.\n#[derive(Debug, Clone)]\npub struct ResourceAny {\n    /// Type URL of the resource.\n    pub type_url: String,\n    /// Serialized resource bytes.\n    pub value: Bytes,\n}\n\n/// Node identification for the client.\n#[derive(Debug, Clone)]\npub struct Node {\n    /// An opaque node identifier.\n    pub id: Option<String>,\n    /// The cluster the node belongs to.\n    pub cluster: Option<String>,\n    /// Locality specifying where the node is running.\n    pub locality: Option<Locality>,\n    /// Free-form string identifying the client type (e.g., \"envoy\", \"grpc\").\n    pub user_agent_name: String,\n    /// Version of the client.\n    pub user_agent_version: String,\n}\n\nimpl Node {\n    /// Create a new Node with the required user agent fields.\n    ///\n    /// Other fields (id, cluster, locality) can be set using builder methods.\n    pub fn new(user_agent_name: impl Into<String>, user_agent_version: impl Into<String>) -> Self {\n        Self {\n            id: None,\n            cluster: None,\n            locality: None,\n            user_agent_name: user_agent_name.into(),\n            user_agent_version: user_agent_version.into(),\n        }\n    }\n\n    /// Set the node ID.\n    pub fn with_id(mut self, id: impl Into<String>) -> Self {\n        self.id = Some(id.into());\n        self\n    }\n\n    /// Set the cluster.\n    pub fn with_cluster(mut self, cluster: impl Into<String>) -> Self {\n        self.cluster = Some(cluster.into());\n        self\n    }\n\n    /// Set the locality.\n    pub fn with_locality(mut self, locality: Locality) -> Self {\n        self.locality = Some(locality);\n        self\n    }\n}\n\n/// Locality information identifying where a node is running.\n#[derive(Debug, Clone, Default)]\npub struct Locality {\n    /// Region the node is in.\n    pub region: String,\n    /// Zone within the region.\n    pub zone: String,\n    /// Sub-zone within the zone.\n    pub sub_zone: String,\n}\n\n/// Error details for NACK responses.\n#[derive(Debug, Clone)]\npub struct ErrorDetail {\n    /// gRPC status code.\n    pub code: i32,\n    /// Error message.\n    pub message: String,\n}\n"
  },
  {
    "path": "xds-client/src/resource/mod.rs",
    "content": "//! Provides abstraction for xDS resources.\n\nuse crate::error::Error;\nuse bytes::Bytes;\nuse std::any::Any;\nuse std::sync::Arc;\n\n#[cfg(feature = \"codegen-prost\")]\npub mod prost;\n\n/// A type URL identifying an xDS resource type.\n///\n/// Format: `type.googleapis.com/<resource_type>`\n/// e.g. `type.googleapis.com/envoy.config.listener.v3.Listener`\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub struct TypeUrl(&'static str);\n\nimpl TypeUrl {\n    /// Create a new type URL from a static string.\n    pub const fn new(url: &'static str) -> Self {\n        Self(url)\n    }\n\n    /// Returns the type URL as a string slice.\n    pub const fn as_str(&self) -> &'static str {\n        self.0\n    }\n}\n\n/// Result of decoding a resource.\n///\n/// This enum represents the three possible outcomes of decoding, following\n/// the pattern used in grpc-go's xDS client (gRFC A46/A88):\n///\n/// - [`Success`](DecodeResult::Success): Resource decoded and validated successfully.\n/// - [`ResourceError`](DecodeResult::ResourceError): Decoding failed but the resource\n///   name was identified. The error can be routed to the specific watcher.\n/// - [`TopLevelError`](DecodeResult::TopLevelError): Decoding failed and the resource\n///   name could not be identified. No specific watcher can be notified.\n#[derive(Debug)]\npub enum DecodeResult<T> {\n    /// Resource decoded and validated successfully.\n    Success {\n        /// The resource name.\n        name: String,\n        /// The decoded resource.\n        resource: T,\n    },\n\n    /// Error decoding a resource whose name could be identified.\n    ///\n    /// This typically occurs when deserialization succeeded (allowing the name\n    /// to be extracted) but subsequent validation failed.\n    /// The error will be reported to watchers interested in this specific resource.\n    ResourceError {\n        /// The resource name that was extracted before the error occurred.\n        name: String,\n        /// The error that occurred during validation.\n        error: Error,\n    },\n\n    /// Error decoding a resource whose name could not be identified.\n    ///\n    /// This typically occurs when deserialization fails early, before the resource\n    /// name can be extracted. Since we don't know which resource this was meant to be,\n    /// no specific watcher can be notified. The error is included in the NACK\n    /// message sent back to the server.\n    TopLevelError(Error),\n}\n\n/// Trait for xDS resources.\n///\n/// # Two-Phase Decoding\n///\n/// Resource decoding is split into two phases to support per-resource error\n/// reporting (gRFC A46/A88):\n///\n/// 1. **Deserialization**: Parse bytes into the [`Message`](Self::Message) type.\n///    If this fails, no resource name is available ([`DecodeResult::TopLevelError`]).\n///\n/// 2. **Validation**: Transform the message into the final resource type.\n///    If this fails, the resource name is known ([`DecodeResult::ResourceError`]).\n///\n/// The provided [`decode`](Self::decode) method orchestrates these phases and\n/// returns the appropriate [`DecodeResult`].\n///\n/// # Resource Deletion in State of the World (SotW)\n///\n/// In SotW xDS, the server sends all resources in each response. The client must\n/// determine whether a previously-seen resource that's absent from a new response\n/// has been deleted or is simply not included.\n///\n/// Per gRFC A53, the behavior depends on the resource type:\n///\n/// - **`ALL_RESOURCES_REQUIRED_IN_SOTW = true`** (default): The server always\n///   sends all resources of this type in each response. If a subscribed\n///   resource is missing, it's treated as deleted. Watchers receive `ResourceDoesNotExist`.\n///   Examples: Listener (LDS), Cluster (CDS).\n///\n/// - **`ALL_RESOURCES_REQUIRED_IN_SOTW = false`**: The resource type allows partial\n///   responses. Missing resources are not treated as deleted; the client continues\n///   using the cached version. Examples: RouteConfiguration (RDS), ClusterLoadAssignment (EDS).\n///\n/// # Example\n///\n/// ```ignore\n/// impl Resource for Listener {\n///     type Message = ListenerProto;\n///\n///     const TYPE_URL: TypeUrl = TypeUrl::new(\"type.googleapis.com/envoy.config.listener.v3.Listener\");\n///\n///     fn deserialize(bytes: Bytes) -> Result<Self::Message, Error> {\n///         ListenerProto::decode(bytes).map_err(Into::into)\n///     }\n///\n///     fn name(message: &Self::Message) -> &str {\n///         &message.name\n///     }\n///\n///     fn validate(message: Self::Message) -> Result<Self, Error> {\n///         // Validation and transformation logic...\n///         Ok(Self { name: message.name, /* ... */ })\n///     }\n/// }\n/// ```\npub trait Resource: Sized + Send + Sync + 'static {\n    /// The deserialized message type (e.g., protobuf-generated struct).\n    type Message;\n\n    /// The xDS type URL for this resource type.\n    const TYPE_URL: TypeUrl;\n\n    /// Whether all subscribed resources must be present in each SotW response.\n    ///\n    /// When `true` (default), if a previously-received resource is absent from a new\n    /// response, it is treated as deleted. Watchers are notified with `ResourceDoesNotExist`.\n    ///\n    /// When `false`, missing resources are not treated as deleted. The client continues\n    /// using the cached version until explicitly removed or updated.\n    ///\n    /// Per gRFC A53:\n    /// - LDS (Listener) and CDS (Cluster): `true`\n    /// - RDS (RouteConfiguration) and EDS (ClusterLoadAssignment): `false`\n    const ALL_RESOURCES_REQUIRED_IN_SOTW: bool = true;\n\n    /// Deserialize bytes into the message type.\n    ///\n    /// This is the first phase of decoding. If this fails, no resource name\n    /// is available and the error becomes a [`DecodeResult::TopLevelError`].\n    fn deserialize(bytes: Bytes) -> Result<Self::Message, Error>;\n\n    /// Extract the resource name from the deserialized message.\n    fn name(message: &Self::Message) -> &str;\n\n    /// Validate and transform the message into the final resource type.\n    ///\n    /// This is the second phase of decoding. If this fails, the resource name\n    /// is known (from [`name`](Self::name)) and the error becomes\n    /// a [`DecodeResult::ResourceError`].\n    fn validate(message: Self::Message) -> Result<Self, Error>;\n}\n\n/// Decode and validate a resource from its serialized bytes.\n///\n/// This function orchestrates the two-phase decoding process:\n/// 1. Deserialize bytes into [`Resource::Message`]\n/// 2. Validate and transform into `T`\n///\n/// Returns the appropriate [`DecodeResult`] based on where (if anywhere) the error occurred.\npub(crate) fn decode<T: Resource>(bytes: Bytes) -> DecodeResult<T> {\n    let message = match T::deserialize(bytes) {\n        Ok(m) => m,\n        Err(e) => return DecodeResult::TopLevelError(e),\n    };\n\n    let name = T::name(&message).to_string();\n\n    match T::validate(message) {\n        Ok(resource) => DecodeResult::Success { name, resource },\n        Err(e) => DecodeResult::ResourceError { name, error: e },\n    }\n}\n\n/// A decoded resource with type-erased value.\n///\n/// Created by the decoder function when a response is received from the xDS server.\n/// The worker stores and dispatches these to watchers, which downcast to the concrete type.\n///\n/// This type is cheaply cloneable (via `Arc`) to support multiple watchers\n/// for the same resource.\n#[derive(Debug, Clone)]\npub struct DecodedResource {\n    type_url: &'static str,\n    name: String,\n    value: Arc<dyn Any + Send + Sync>,\n}\n\nimpl DecodedResource {\n    /// Create a new decoded resource from a concrete resource type.\n    pub fn new<T: Resource>(name: String, resource: T) -> Self {\n        Self {\n            type_url: T::TYPE_URL.as_str(),\n            name,\n            value: Arc::new(resource),\n        }\n    }\n\n    /// Returns the type URL of the resource.\n    pub fn type_url(&self) -> &'static str {\n        self.type_url\n    }\n\n    /// Returns the name of the resource.\n    pub fn name(&self) -> &str {\n        &self.name\n    }\n\n    /// Downcast to a concrete type wrapped in `Arc`.\n    ///\n    /// Returns `None` if the type does not match.\n    ///\n    /// This returns `Arc<T>` because `DecodedResource` may be cloned and shared\n    /// across multiple watchers. Each watcher receives a reference to the same\n    /// underlying resource data.\n    ///\n    /// This method clones the internal `Arc` (cheap refcount increment) and\n    /// attempts to downcast it to the concrete type.\n    pub fn downcast<T: Resource>(&self) -> Option<Arc<T>> {\n        Arc::clone(&self.value).downcast().ok()\n    }\n\n    /// Borrow the decoded resource and downcast to a concrete type reference.\n    ///\n    /// Returns `None` if the type does not match.\n    pub fn downcast_ref<T: Resource>(&self) -> Option<&T> {\n        self.value.downcast_ref()\n    }\n}\n\n/// Type-erased decoder function.\n///\n/// Created by `XdsClient::watch()` capturing the resource type `T`.\n/// The worker stores this per type_url and uses it to decode incoming resources.\n///\n/// Returns a [`DecodeResult`] indicating success or the type of failure.\npub type DecoderFn = Box<dyn Fn(Bytes) -> DecodeResult<DecodedResource> + Send + Sync>;\n"
  },
  {
    "path": "xds-client/src/resource/prost.rs",
    "content": "//! `prost` codec-specific resources.\n"
  },
  {
    "path": "xds-client/src/runtime/mod.rs",
    "content": "//! Provides abstraction for async runtimes.\n\nuse std::future::Future;\nuse std::time::Duration;\n\n#[cfg(feature = \"rt-tokio\")]\npub mod tokio;\n\n/// Trait for async runtime operations.\n///\n/// This abstraction allows the xDS client to be runtime-agnostic.\n// TODO: unify with the grpc-rust runtime trait\npub trait Runtime: Send + Sync + Clone + 'static {\n    /// Spawn a future to run in the background.\n    fn spawn<F>(&self, future: F)\n    where\n        F: Future<Output = ()> + Send + 'static;\n\n    /// Sleep for the given duration.\n    fn sleep(&self, duration: Duration) -> impl Future<Output = ()> + Send;\n}\n"
  },
  {
    "path": "xds-client/src/runtime/tokio.rs",
    "content": "//! `tokio` based runtime implementation.\n\nuse crate::runtime::Runtime;\nuse std::future::Future;\nuse std::time::Duration;\n\n/// Tokio-based runtime implementation.\n#[derive(Clone, Debug, Default)]\npub struct TokioRuntime;\n\nimpl Runtime for TokioRuntime {\n    fn spawn<F>(&self, future: F)\n    where\n        F: Future<Output = ()> + Send + 'static,\n    {\n        tokio::spawn(future);\n    }\n\n    async fn sleep(&self, duration: Duration) {\n        tokio::time::sleep(duration).await;\n    }\n}\n"
  },
  {
    "path": "xds-client/src/transport/mod.rs",
    "content": "//! Provides abstraction for transport layers.\n\nuse crate::client::config::ServerConfig;\nuse crate::error::Result;\nuse bytes::Bytes;\nuse std::future::Future;\n\n#[cfg(feature = \"transport-tonic\")]\npub mod tonic;\n\nmod sealed {\n    pub trait Sealed {}\n}\n\n/// Factory for creating xDS transport streams.\n///\n/// This abstraction allows for different transport implementations:\n/// - Tonic-based gRPC transport\n/// - The upcoming gRPC Rust transport\n/// - Mock transport for testing\n/// - Other custom transports\npub trait Transport: Send + Sync + 'static {\n    /// The stream type produced by this transport.\n    type Stream: TransportStream;\n\n    /// Creates a new bidirectional ADS stream to the xDS server.\n    ///\n    /// # Arguments\n    ///\n    /// * `initial_requests` - Requests to send immediately when establishing the stream.\n    ///   This is critical for xDS servers that don't send response headers until\n    ///   they receive the first request (prevents deadlock).\n    ///\n    /// This may be called multiple times for reconnection.\n    fn new_stream(\n        &self,\n        initial_requests: Vec<Bytes>,\n    ) -> impl Future<Output = Result<Self::Stream>> + Send;\n}\n\n/// A bidirectional byte stream for xDS ADS communication.\n///\n/// Raw byte transport where the bytes are serialized DiscoveryRequest/DiscoveryResponse\n/// (de)serialization is handled at the xDS client worker layer.\n// Sealed for now to limit API surface.\npub trait TransportStream: sealed::Sealed + Send + 'static {\n    /// Send serialized DiscoveryRequest bytes to the server.\n    fn send(&mut self, request: Bytes) -> impl Future<Output = Result<()>> + Send;\n\n    /// Receive serialized DiscoveryResponse bytes from the server.\n    ///\n    /// Returns:\n    /// - `Ok(Some(bytes))` - Received a response.\n    /// - `Ok(None)` - Stream closed normally.\n    /// - `Err(_)` - Stream error (connection dropped, etc.)\n    fn recv(&mut self) -> impl Future<Output = Result<Option<Bytes>>> + Send;\n}\n\n#[cfg(feature = \"transport-tonic\")]\nimpl sealed::Sealed for tonic::TonicAdsStream {}\n\n/// Factory for creating transports to xDS servers.\n///\n/// This abstraction allows the client to create transports on-demand,\n/// enabling features like:\n/// - Server fallback (gRFC A71): Try backup servers when primary fails\n/// - Connection pooling: Reuse connections to the same server\n///\n/// Implementations may hold configuration (e.g., TLS settings) that applies\n/// to all servers.\n///\n/// # Example\n///\n/// ```ignore\n/// use xds_client::{ServerConfig, TransportBuilder};\n///\n/// struct MyTransportBuilder { /* ... */ }\n///\n/// impl TransportBuilder for MyTransportBuilder {\n///     type Transport = MyTransport;\n///\n///     async fn build(&self, server: &ServerConfig) -> Result<Self::Transport> {\n///         // Create transport connected to server.uri()\n///     }\n/// }\n/// ```\npub trait TransportBuilder: Send + Sync + 'static {\n    /// The transport type produced by this builder.\n    type Transport: Transport;\n\n    /// Build a transport connected to the given server.\n    ///\n    /// This may be called multiple times for reconnection or fallback.\n    /// Implementations may cache/pool connections internally.\n    fn build(&self, server: &ServerConfig) -> impl Future<Output = Result<Self::Transport>> + Send;\n\n    // Future extensions:\n    // - `fn close(&self, server: &ServerConfig)` for explicit connection cleanup\n    // - Metrics/observability hooks\n}\n"
  },
  {
    "path": "xds-client/src/transport/tonic.rs",
    "content": "//! `tonic` based transport implementation.\n//!\n//! This transport uses tonic's low-level `Grpc` client with a `BytesCodec`\n//! to send and receive raw bytes, allowing the xDS client layer to handle\n//! serialization/deserialization independently.\n\nuse crate::client::config::ServerConfig;\nuse crate::error::{Error, Result};\nuse crate::transport::{Transport, TransportBuilder, TransportStream};\nuse bytes::{Buf, BufMut, Bytes};\nuse http::uri::PathAndQuery;\nuse tokio::sync::mpsc;\nuse tokio_stream::StreamExt as _;\nuse tonic::client::Grpc;\nuse tonic::codec::{Codec, DecodeBuf, Decoder, EncodeBuf, Encoder};\nuse tonic::transport::Channel;\nuse tonic::{Status, Streaming};\n\n/// The gRPC path for the ADS StreamAggregatedResources RPC.\nconst ADS_PATH: &str =\n    \"/envoy.service.discovery.v3.AggregatedDiscoveryService/StreamAggregatedResources\";\n\nconst ADS_CHANNEL_BUFFER_SIZE: usize = 16;\n\n/// A codec that passes bytes through without serialization.\n///\n/// This allows us to handle serialization in the xDS client layer\n/// rather than in the transport layer.\n#[derive(Debug, Clone, Copy)]\nstruct BytesCodec;\n\nimpl Codec for BytesCodec {\n    type Encode = Bytes;\n    type Decode = Bytes;\n    type Encoder = BytesEncoder;\n    type Decoder = BytesDecoder;\n\n    fn encoder(&mut self) -> Self::Encoder {\n        BytesEncoder\n    }\n\n    fn decoder(&mut self) -> Self::Decoder {\n        BytesDecoder\n    }\n}\n\n#[derive(Debug)]\nstruct BytesEncoder;\n\nimpl Encoder for BytesEncoder {\n    type Item = Bytes;\n    type Error = Status;\n\n    fn encode(\n        &mut self,\n        item: Self::Item,\n        dst: &mut EncodeBuf<'_>,\n    ) -> std::result::Result<(), Self::Error> {\n        dst.put_slice(&item);\n        Ok(())\n    }\n}\n\n#[derive(Debug)]\nstruct BytesDecoder;\n\nimpl Decoder for BytesDecoder {\n    type Item = Bytes;\n    type Error = Status;\n\n    fn decode(\n        &mut self,\n        src: &mut DecodeBuf<'_>,\n    ) -> std::result::Result<Option<Self::Item>, Self::Error> {\n        Ok(Some(src.copy_to_bytes(src.remaining())))\n    }\n}\n\n/// Factory for creating ADS streams using tonic.\n#[derive(Clone, Debug)]\npub struct TonicTransport {\n    channel: Channel,\n}\n\nimpl TonicTransport {\n    /// Create a transport from an existing tonic [`Channel`].\n    ///\n    /// Use this when you need custom channel configuration (e.g., TLS, timeouts).\n    ///\n    /// # Example\n    ///\n    /// ```ignore\n    /// use tonic::transport::{Certificate, Channel, ClientTlsConfig};\n    ///\n    /// let tls = ClientTlsConfig::new()\n    ///     .ca_certificate(Certificate::from_pem(ca_cert))\n    ///     .domain_name(\"xds.example.com\");\n    ///\n    /// let channel = Channel::from_static(\"https://xds.example.com:443\")\n    ///     .tls_config(tls)?\n    ///     .connect()\n    ///     .await?;\n    ///\n    /// let transport = TonicTransport::from_channel(channel);\n    /// ```\n    pub fn from_channel(channel: Channel) -> Self {\n        Self { channel }\n    }\n\n    /// Connect to an xDS server with default settings.\n    ///\n    /// For custom configuration (TLS, timeouts, etc.), use [`from_channel`](Self::from_channel).\n    pub async fn connect(uri: impl Into<String>) -> Result<Self> {\n        let uri: String = uri.into();\n        let channel = Channel::from_shared(uri)\n            .map_err(|e| Error::Connection(e.to_string()))?\n            .connect()\n            .await\n            .map_err(|e| Error::Connection(e.to_string()))?;\n        Ok(Self { channel })\n    }\n}\n\n/// Builder for creating [`TonicTransport`] instances.\n///\n/// This implements [`TransportBuilder`] and can be used with [`XdsClientBuilder`]\n/// to enable server fallback support.\n///\n/// For connections requiring TLS or custom channel configuration, see the\n/// example in [`TonicTransport::from_channel`].\n///\n/// # Example\n///\n/// ```ignore\n/// use xds_client::{ClientConfig, Node, TonicTransportBuilder, XdsClient};\n///\n/// let transport_builder = TonicTransportBuilder::new();\n/// let config = ClientConfig::new(node, \"http://xds.example.com:18000\");\n/// let client = XdsClient::builder(config, transport_builder, codec, runtime).build();\n/// ```\n#[derive(Debug, Clone, Default)]\npub struct TonicTransportBuilder {\n    // Future extensions:\n    // - TLS configuration (requires tonic TLS feature)\n    // - Connection timeout settings\n    // - Keep-alive configuration\n    // - Connection pooling settings\n    // - Per-server credential overrides (via ServerConfig.extensions)\n}\n\nimpl TonicTransportBuilder {\n    /// Create a new transport builder with default settings.\n    pub fn new() -> Self {\n        Self::default()\n    }\n}\n\nimpl TransportBuilder for TonicTransportBuilder {\n    type Transport = TonicTransport;\n\n    async fn build(&self, server: &ServerConfig) -> Result<Self::Transport> {\n        let channel = Channel::from_shared(server.uri().to_string())\n            .map_err(|e| Error::Connection(e.to_string()))?\n            .connect()\n            .await\n            .map_err(|e| Error::Connection(e.to_string()))?;\n\n        Ok(TonicTransport::from_channel(channel))\n    }\n}\n\nimpl Transport for TonicTransport {\n    type Stream = TonicAdsStream;\n\n    async fn new_stream(&self, initial_requests: Vec<Bytes>) -> Result<Self::Stream> {\n        let mut grpc = Grpc::new(self.channel.clone());\n\n        grpc.ready()\n            .await\n            .map_err(|e| Error::Connection(e.to_string()))?;\n\n        let (tx, rx) = mpsc::channel::<Bytes>(ADS_CHANNEL_BUFFER_SIZE);\n\n        // Create a stream that first yields initial requests, then reads from the channel.\n        // This ensures data is available immediately when the stream is polled,\n        // preventing deadlock with servers that don't send response headers\n        // until they receive the first request message.\n        let initial_stream = tokio_stream::iter(initial_requests);\n        let channel_stream = tokio_stream::wrappers::ReceiverStream::new(rx);\n        let request_stream = initial_stream.chain(channel_stream);\n\n        let path = PathAndQuery::from_static(ADS_PATH);\n\n        let response = grpc\n            .streaming(tonic::Request::new(request_stream), path, BytesCodec)\n            .await\n            .map_err(Error::Stream)?;\n\n        Ok(TonicAdsStream {\n            sender: tx,\n            receiver: response.into_inner(),\n        })\n    }\n}\n\n/// A bidirectional ADS stream backed by tonic.\n#[derive(Debug)]\npub struct TonicAdsStream {\n    sender: mpsc::Sender<Bytes>,\n    receiver: Streaming<Bytes>,\n}\n\nimpl TransportStream for TonicAdsStream {\n    async fn send(&mut self, request: Bytes) -> Result<()> {\n        self.sender\n            .send(request)\n            .await\n            .map_err(|_| Error::StreamClosed)?;\n        Ok(())\n    }\n\n    async fn recv(&mut self) -> Result<Option<Bytes>> {\n        match self.receiver.message().await {\n            Ok(msg) => Ok(msg),\n            Err(status) => Err(Error::Stream(status)),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use envoy_types::pb::envoy::service::discovery::v3::{\n        DeltaDiscoveryRequest, DeltaDiscoveryResponse, DiscoveryRequest, DiscoveryResponse,\n        aggregated_discovery_service_server::{\n            AggregatedDiscoveryService, AggregatedDiscoveryServiceServer,\n        },\n    };\n    use prost::Message;\n    use std::net::SocketAddr;\n    use std::pin::Pin;\n    use tokio::net::TcpListener;\n    use tokio_stream::Stream;\n    use tokio_stream::wrappers::TcpListenerStream;\n    use tonic::{Request, Response, Status};\n\n    /// Mock ADS server that echoes back a response for each request.\n    struct MockAdsServer;\n\n    #[tonic::async_trait]\n    impl AggregatedDiscoveryService for MockAdsServer {\n        type StreamAggregatedResourcesStream =\n            Pin<Box<dyn Stream<Item = std::result::Result<DiscoveryResponse, Status>> + Send>>;\n\n        async fn stream_aggregated_resources(\n            &self,\n            request: Request<tonic::Streaming<DiscoveryRequest>>,\n        ) -> std::result::Result<Response<Self::StreamAggregatedResourcesStream>, Status> {\n            let mut inbound = request.into_inner();\n\n            let outbound = async_stream::try_stream! {\n                while let Some(req) = inbound.next().await {\n                    let req = req?;\n                    let response = DiscoveryResponse {\n                        version_info: \"1\".to_string(),\n                        type_url: req.type_url.clone(),\n                        nonce: \"nonce-1\".to_string(),\n                        resources: vec![],\n                        ..Default::default()\n                    };\n                    yield response;\n                }\n            };\n\n            Ok(Response::new(Box::pin(outbound)))\n        }\n\n        type DeltaAggregatedResourcesStream =\n            Pin<Box<dyn Stream<Item = std::result::Result<DeltaDiscoveryResponse, Status>> + Send>>;\n\n        async fn delta_aggregated_resources(\n            &self,\n            _request: Request<tonic::Streaming<DeltaDiscoveryRequest>>,\n        ) -> std::result::Result<Response<Self::DeltaAggregatedResourcesStream>, Status> {\n            Err(Status::unimplemented(\"delta not supported in mock\"))\n        }\n    }\n\n    async fn start_mock_server() -> SocketAddr {\n        let listener = TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n        let addr = listener.local_addr().unwrap();\n\n        tokio::spawn(async move {\n            tonic::transport::Server::builder()\n                .add_service(AggregatedDiscoveryServiceServer::new(MockAdsServer))\n                .serve_with_incoming(TcpListenerStream::new(listener))\n                .await\n                .unwrap();\n        });\n\n        // Give the server a moment to start\n        tokio::time::sleep(std::time::Duration::from_millis(50)).await;\n        addr\n    }\n\n    #[tokio::test]\n    async fn test_tonic_transport_connect_and_stream() {\n        let addr = start_mock_server().await;\n        let uri = format!(\"http://{addr}\");\n\n        let transport = TonicTransport::connect(&uri).await.unwrap();\n\n        let request = DiscoveryRequest {\n            type_url: \"type.googleapis.com/envoy.config.listener.v3.Listener\".to_string(),\n            resource_names: vec![\"listener-1\".to_string()],\n            ..Default::default()\n        };\n        let request_bytes: Bytes = request.encode_to_vec().into();\n\n        let mut stream = transport.new_stream(vec![request_bytes]).await.unwrap();\n\n        let response_bytes = stream.recv().await.unwrap().unwrap();\n        let response = DiscoveryResponse::decode(response_bytes).unwrap();\n\n        assert_eq!(response.version_info, \"1\");\n        assert_eq!(\n            response.type_url,\n            \"type.googleapis.com/envoy.config.listener.v3.Listener\"\n        );\n        assert_eq!(response.nonce, \"nonce-1\");\n    }\n}\n"
  }
]